Fábio Almeida, Platform Engineering Team Lead, @SISCOG | 6 min leitura
___________
O nosso percurso com a Integração Contínua (CI) começou há mais de uma década, quando um grupo de programadores quis explorar o potencial dos processos de testes automatizados. Numa tentativa de assegurar um nível básico de qualidade e promover a redução de ineficiências criadas por builds falhadas, este grupo implementou uma prova de conceito utilizando o Jenkins para construir e testar binários. Inicialmente, este esforço não gerou muito entusiasmo, pois muitos programadores preferiam manter as suas rotinas manuais de build e teste. No entanto, a persistência desses pioneiros provou-se importante para a SISCOG.
Ao longo dos anos, o que começou como uma iniciativa algo marginal tornou-se numa parte vital do nosso fluxo de desenvolvimento de software. A transformação foi significativamente acelerada há cinco anos, após uma migração tecnológica complexa, que precipitou a execução de builds diárias de todos os componentes. Testes unitários, de integração e end-to-end foram rapidamente incorporados, levando a uma melhoria substancial na estabilidade e na qualidade do código. Hoje, a Integração Contínua (CI) está profundamente enraizada nos nossos processos, tornando-nos mais eficientes e o nosso software mais fiável, o que revela a importância da inovação contínua e da adaptação no desenvolvimento de software. É isto que vamos explorar no resto deste artigo.
OS PRIMEIROS PASSOS
Logo após o surgimento do Jenkins, alguns dos nossos programadores sentiram a necessidade de trazer o seu poder para o nosso quotidiano. Eles propuseram-se a demonstrar a utilidade destas ferramentas e processos automatizados para a empresa. Como resultado, foi criada uma prova de conceito baseada no Jenkins.
A ideia inicial era fazer com que conjuntos de testes automatizados, que já eram executados localmente, fossem executados automaticamente, a fim de garantir um nível adicional de qualidade dos nossos Modos Automáticos(1). Quando esta prova de conceito foi apresentada à empresa, não despertou um interesse significativo. Alguns diziam: "Já executo testes na minha máquina", enquanto outros comentavam: "A nossa equipa de testes já testa o sistema".
“Hoje, a Integração Contínua está profundamente enraizada nos nossos processos, tornando-nos mais eficientes e o nosso software mais fiável.”
______________________
Sendo os pioneiros da Integração Contínua na SISCOG, estes programadores não estavam prestes a desistir perante uma pequena adversidade. E os mecanismos automáticos continuaram a evoluir e a expandir-se.
Pouco depois, as compilações diárias e os testes automatizados dos nossos produtos estavam a acontecer todos os dias (pelo menos para a equipa destes programadores). Os binários estavam a ser publicados numa pasta de rede para que os programadores os pudessem utilizar e, em caso de falha, os autores dos últimos commits eram avisados de quaisquer erros de compilação. Eventualmente, alguns programadores implementaram ferramentas para os alertar se a sua compilação local aumentasse o número de warnings de compilação em comparação com a última compilação diária bem-sucedida.
Lenta, mas seguramente, as pessoas começaram a depender deste mecanismo diário e a estabilidade melhorou: a quantidade de e-mails a circular, exigindo saber quem tinha partido a compilação, diminuiu consideravelmente (infelizmente, não temos estatísticas). Em vez de receberem uma mensagem humana de alguém a reclamar que passou o dia a depurar o erro de outra pessoa, os programadores recebiam um e-mail de um serviço automatizado a pedir educadamente que verificassem se o seu trabalho recente poderia ter causado o erro.
Mas mesmo assim, as coisas estavam a acontecer debaixo do radar. A empresa reconhecia a existência do Jenkins, mas o processo oficial de desenvolvimento não o incluía como uma ferramenta de validação. No entanto, os programadores aprenderam a depender destes mecanismos, com muitos a confiarem fortemente neles. Alguns programadores, como eu, começavam o dia por ir buscar os binários produzidos pelo Jenkins durante a noite.
Contudo, nessa altura, ainda existia uma grande lacuna: a maioria das customizações dos nossos clientes não estavam a ser abrangidas por estes processos automáticos. Até que, há cinco anos, tudo mudou, quase da noite para o dia.
PONTO DE VIRAGEM
Como as práticas comuns ditam hoje em dia: testar antes de mudar! Quando confrontados com grandes mudanças, nós programadores sentimo-nos mais confortáveis quando temos um conjunto abrangente de validações para ajudar a garantir a qualidade dessas mudanças. E foi isso que nos empurrou para o proverbial "lado negro".
Há cinco anos, quando confrontados com uma migração de software complexa repleta de desafios técnicos, procurámos a tranquilidade da Integração Contínua. Em menos de uma semana, todas as especificações dos clientes estavam a ser compiladas diariamente; em menos de um mês, os testes unitários e de integração começaram a ser executados; e pouco tempo depois, os testes end-to-end juntaram-se à festa da automatização.
Isso permitiu-nos enfrentar a incerteza de mudar o nosso software com uma rede de segurança que nos daria algum feedback sobre as mudanças submetidas.
Com execuções periódicas (principalmente, a cada hora e diárias) a crescer e totalmente integradas no nosso fluxo de desenvolvimento diário, começámos a explorar formas adicionais de garantir a qualidade e estabilidade do nosso software e das alterações que produzimos. "Mais testes" é sempre uma resposta (e continuámos a fazê-lo também), mas havia algo que ainda não tínhamos experimentado, algo totalmente aceite nos processos de desenvolvimento atuais: compilar e testar antes de aceitar alterações.
Dado que usamos o Gerrit Code Review como plataforma de revisão de código, foi uma questão "simples" de adicionar builds quando um programador envia um Change Request para o Gerrit.
O cenário de hoje é bastante diferente de há uma década atrás. Todas as nossas aplicações são construídas e testadas para cada Change Request e no final do dia. Temos testes unitários, de integração e end-to-end que são executados todas as noites para encontrar regressões e erros. Testes de performance e qualidade também são executados aos fins de semana, além de testes funcionais conduzidos do ponto de vista do utilizador.
CONCLUSÕES
A mudança é difícil; especialmente quando se desenvolve software há mais de 35 anos, como é o caso da SISCOG. Carregar tanta bagagem às costas às vezes torna-se difícil. Quando se começa por partilhar o tempo de uma máquina Lisp entre programadores, pode ser difícil ver o valor de automatizar processos pessoais para serem executados em máquinas desocupadas.
Não estou a trazer nada de novo para a discussão ao dizer que há um valor real em empregar estas práticas. Utilizar mecanismos de Integração Contínua (CI) nos fluxos de trabalho de desenvolvimento de software ajuda-nos a avançar mais rapidamente e com maior confiança de que as mudanças feitas são sólidas e seguras. A verdade é que, o tempo para descobrir certos tipos de bugs melhorou, com alguns tipos de bugs tendo sido completamente erradicados (por exemplo, “estragar” a build é agora uma coisa do passado). Além disso, o precioso tempo dos programadores (todos conhecemos o adágio: "o tempo do programador é mais caro do que o tempo do computador") pode ser alocado a tarefas mais importantes: introduzir mais bugs!
“Utilizar mecanismos de Integração Contínua nos fluxos de trabalho de desenvolvimento de software ajuda-nos a avançar mais rapidamente e com maior confiança de que as mudanças feitas são sólidas e seguras.”
______________________
Para mim, a questão mais importante que surgiu ao longo da nossa experiência com Integração Contínua é: como podemos introduzir mais estabilidade, melhorar a qualidade das verificações, avançar mais rapidamente e entregar mais valor aos nossos clientes? Devemos escrever mais testes unitários? Ou serão os testes end-to-end a resposta? Devemos ser mais seletivos sobre o que construímos e testamos ao validar um Change Request? Ou devemos construir e testar tudo para cada Change Request?
Infelizmente, não existem balas de prata. Pessoalmente, acredito no equilíbrio, portanto, todas estas estratégias são necessárias para alcançar uma qualidade superior.
No entanto, estamos no caminho certo, com muitos carris ainda por percorrer.
(1) Modo Automático é um modo de operação na SISCOG Suite para o planeamento otimizado de recursos, como veículos e pessoal Para mais informação ver artigo “A Lâmpada Mágica”.