O processo de garantia de qualidade em um ambiente ágil - Ship It!
O ambiente (desafio)
Imagine um ambiente de trabalho onde temos mais de 30 desenvolvedores realizando uma média de 8 a 10 deploys (lançamentos) em produção por dia e revisando mais de 180 pull requests (PR) por mês. Todos os deploys são feitos de forma automática via Slack para ambientes de teste e produção.
Já pensou no caos que isso pode gerar? Bugs em produção acabam sendo um problema inevitável. Mas como fazemos para reduzir o risco, mantendo a agilidade das equipes?
A definição dos processos deve considerar as etapas iniciais do ciclo de desenvolvimento de software. Focando em qualidade desde a etapa de planejamento, envolvendo diferentes stakeholders: Product Owner, Analista de Negócio, Clientes, Quality Assurance e time de desenvolvimento. Na Resultados Digitais temos como boa prática as funcionalidades serem escritas em forma de testes de aceitação, ou seja, criamos especificações executáveis, dinâmicas, e que comprovam um funcionamento esperado (pelos diferentes stakeholders) e correto (testes passando).
Gherkin (Linguagem de Comunicação)
Em fase de planejamento as funcionalidades são descritas utilizando a linguagem Gherkin. Descrevemos a funcionalidade de forma natural, explicitando cenários de teste e usando exemplos para diversificá-los. O grande benefício deste processo é fomentar a comunicação entre diversos stakeholders, fazendo com que as implementações sejam discutidas, pensadas, estimadas e validadas.
Gerando comunicação nessa fase inicial e descrevendo funcionalidades em forma de testes de aceitação temos um grande valor sendo gerado: uma documentação ágil que permanecesse ativa - testes continuamente sendo executados (atualmente utilizamos o framework Cucumber para automatizar os testes escritos em Gherkin) . Dessa forma o processo de qualidade se inicia em fase de planejamento, gerando testes de aceitação, antes que qualquer linha de código seja escrita. Um fator importante é a utilização desses testes como Definition of Done (DoD, definição de pronto), confirmando que ao entregar a funcionalidade, com os cenários de testes de aceitação passando, a temos completa e entregue.
Código e testes unitários
Tendo os testes de aceitação escritos, desenvolvedores começam a implementar as funcionalidades, escrevendo testes unitários e praticando Test Driven Development (TDD, desenvolvimento orientado a testes). Os testes de aceitação escritos anteriormente servem de base para a prática de TDD, sabendo o que está sendo coberto em nível de aceitação e o que precisa ser garantido a nível unitário (um dos grandes questionamentos dos desenvolvedores ao praticar TDD é justamente o fato de não saber por onde começar a escrever os testes unitários). Garantimos também que testes não serão redundantes, ou seja, testes unitários validam cenários que os testes de aceitação não cobrem.
Outro fator importante na esfera de testes unitários é a porcentagem de cobertura de código. Na Resultados Digitais mantemos uma alta cobertura de código, atualmente trabalhando na linha dos 90%. Formamos uma suíte com mais de 4000 testes, que são executados sempre que código é enviado (push) ao repositório.
Para manter uma meta de cobertura de código desse nível é necessário que a cultura de qualidade faça parte da cultura da empresa. Ou seja, os desenvolvedores se comprometem e têm a responsabilidade, mantendo seu código testado como algo natural em seu dia-a-dia. Antes de submeter qualquer código para o repositório, o desenvolvedor se certifica de que os testes estão passando, estão com alta cobertura e têm qualidade.
Na Resultados Digitais utilizamos o Code Climate para realizar revisões automáticas de código. No momento em que é aberto um pull request no GitHub, a ferramenta realiza a revisão estática de código e fornece uma pontuação para sua qualidade. A pontuação varia entre A e F e aponta melhorias ou declínios. É parte da cultura mantermos uma boa pontuação, refatorando sempre que necessário.
Pull request e revisão de código
Seguindo o processo de qualidade, após o código ser enviado ao repositório, testes passando, tanto a nível unitário quanto a nível de aceitação, um PR pode ser aberto.
É responsabilidade das equipes realizarem as revisões de PR, sendo que um desenvolvedor (além do autor do PR) é encarregado de revisar o código, os testes e demais alterações descritas no PR.
Quem realiza a revisão comenta no próprio PR suas sugestões e questionamentos, onde o autor responde e refatora o código caso necessário. Comunicação, troca de experiência e um repositório de conhecimento é formado nesse ponto do processo.
Quem realiza a revisão deve considerar:
Boas práticas de Clean Code
Código DRY - Don't Repeat Yourself
Testes de Aceitação não ambíguos
Cobertura de Testes Unitários > 90%
Qualidade de Testes Unitários - Boas variações de cenários
Adequação do código ao guideline de desenvolvimento
Para auxiliar as revisões, temos alguns guidelines específicos para cada linguagem utilizada na RD (Ruby, JavaScript, CSS/HTML, entre outros).
Após o processo de revisão ter sido concluído, a funcionalidade está pronta para entrar em produção. Portanto podemos partir para a etapa de deploy.
Antes de realizar a entrega, ou seja, o deploy em ambiente de produção, consideramos sua criticidade:
Tendo os conta os pontos citados acima, optamos por realizar o deploy em um ambiente pré-produção (e.g. staging) para que mais testes sejam realizados.
Ainda considerando a criticade, outra opção é realizar o lançamento de forma parcial, liberando a atualização para uma parte dos usuários, o chamado Canary Deployment. Após confirmado que não tivemos problemas, o restante da base de usuários alcança o novo código.
Confirmado que não tivemos problemas em ambiente de staging, ou que a criticidade da alteração não é alta, podemos seguir para o deploy em produção. Ele é realizado de forma automática e leva em conta o fato de que todos testes estão passando.
Após o novo código entrar em produção, o responsável deve monitorar o sistema para assegurar que não tivemos impacto negativo.
Neste post apresentamos o processo de garantia qualidade da Resultados Digitais. Um processo ágil, que valoriza a comunicação sobre a documentação, com o mínimo de testes manuais e com a equipe de desenvolvimento como principal responsável pela qualidade do código.
Dessa forma conseguimos fazer com que a qualidade de software seja parte da cultura da empresa, mantendo a escalabilidade dos produtos aqui desenvolvidos e, principalmente, mantendo a agilidade de nossa equipe.