• Nenhum resultado encontrado

2.12 O MANIFESTO ÁGIL

2.12.2 A programação extrema e o Desenvolvimento Dirigido a Testes

Segundo Beck (2000), o Extreming Programming (XP) resultou da experiência do desenvolvimento do projeto C3 Payroll na Chrysler, projeto que consistia no desenvolvimento de um sistema de folha de pagamento. A partir do sucesso de XP no desenvolvimento do referido sistema, o processo passou a ser mais disseminado e popularizado, principalmente, no ambiente da orientação a objetos. Anteriormente ao projeto C3, o processo já tinha recebido importantes contribuições oriundas do desenvolvimento utilizando Smalltalk e de autores da área como Kent Beck, Martin Fowler e Ward Cunningham. Grande parte do sucesso de XP é devido a sua simplicidade e objetividade, possibilitando a disponibilidade do software ao cliente de forma rápida e eficiente, sem descartar, no entanto, a possibilidade de mudanças, visando cada vez mais ao melhoramento do sistema.

O XP incorpora em sua metodologia uma série de elementos e práticas, tais como: A programação em pares; revisões de código; desenvolvimento orientado a testes; simplicidade e clareza no código, esperando mudanças nos requisitos do cliente; comunicação frequente com o cliente e entre os programadores (SOMMERVILLE, 2009). Uma das principais metodologias do XP, utilizada na fase de execução/monitoramento e controle na gestão de projetos de desenvolvimento de software com o GP2 é o TDD, explicado na seção a seguir.

2.12.2.1 Desenvolvimento Dirigido a Testes (TDD)

Test-Driven Development (TDD, do português Desenvolvimento Orientado a Testes)

consiste em um método ágil de desenvolvimento de software, o qual propõe uma abordagem baseada na repetição de ciclos curtos de desenvolvimento (BECK, 2003). O ciclo básico de uma abordagem baseada em TDD sugere três etapas: inicialmente o desenvolvedor escreve um caso de teste automatizado, o qual precisa falhar para assim definir a demanda de melhoria ou desenvolvimento da nova função; em seguida o desenvolvedor escreve a mínima quantidade de código suficiente para que o teste passe; por fim, o desenvolvedor refatora o código para padrões aceitáveis de codificação. (SHORE, 2008)

Para Ambler (2010), tal como acontece com os testes tradicionais, quanto maior o perfil de risco do sistema, mais completos os testes precisam ser, ressaltando ainda que em ambos os testes, tradicionais ou TDD, não se está buscando a perfeição, em vez disso, está testando a importância do sistema.

Watkins (2009) discorre a respeito do feedback dos desenvolvedores adeptos ao TDD, mostrando que a técnica é recebida como uma abordagem muito valiosa. Complementa ainda que, é grande a necessidade de compreensão dos requisitos em nível de detalhe suficiente para capacidade de projetar um teste que mostre que o código atende ao requisito. A sequência do fluxo do processo de TDD é apresentada na Figura 24 e descrita a seguir (Beck 2000 apud PEREIRA, 2014).

Escrever um Teste (Write a Test): Em TDD, a implementação de cada nova

funcionalidade começa com a escrita de um teste. Este teste deve, inevitavelmente, falhar, uma vez que é escrito antes do recurso ser implementado. É fundamental que o teste falhe, do contrário, ou o recurso "novo" proposto já existe ou o teste está com defeito. Para escrever um teste, o desenvolvedor deve entender claramente a especificação e requisitos da função. O desenvolvedor pode fazer isso por meio de Casos de Uso ou Estórias de Usuários para cobrir os requisitos e as condições de exceção, e pode escrever o teste em qualquer framework de teste apropriado para o ambiente de software. O referido teste também pode ser uma modificação de um teste existente. Essa característica é o grande diferencial do Desenvolvimento Orientado a Testes, ante a prática comum de escrever testes de unidade após o código estar escrito: o desenvolvedor foca nos requisitos antes de escrever o código, uma diferença sutil, mas importante;

Verificar se o teste falha (Check if the test fails): Isso confirma que o teste está

funcionando corretamente e que o novo teste não passa sem a necessidade de um novo código. Esta etapa também testa o próprio teste em si: exclui a possibilidade de que o novo teste sempre passa, e, portanto, é inútil;

Escrever Código de Produção (Write Production Code): O próximo passo é escrever

um código que faça com que o teste passe. O código escrito nesta fase não é perfeito, e pode, por exemplo, passar no teste de uma maneira deselegante. Isso é aceitável, pois as próximas etapas irão melhorar e aprimorar o código. Neste momento, a única finalidade do código é passar no teste. Nenhuma nova (e, portanto, não testada) funcionalidade deve ser prevista e permitida nesta fase;

Executar todos os testes (Run all tests): Se todos os casos de teste passarem, o

desenvolvedor pode ter a certeza de que o código preenche todos os requisitos testados. Este é um bom ponto de partida para começar a etapa final;

Limpar o código e Refatorar (Clean up code e Refactor): Nesse momento, o código

deve ser limpo, se necessário. Deve-se mover o código de onde era conveniente para passar no teste para onde ele pertence logicamente. São removidas quaisquer duplicações, certificar-se quanto aos nomes de variáveis, bem como se métodos representam o seu uso. É importante utilizar a regra de Beck (2000) de Design Simples quanto à clareza do código. Ao reexecutar os casos de teste, o desenvolvedor deve ter certeza de que o código refatorado não é prejudicial à outra funcionalidade existente. O conceito de eliminação de duplicações é importante em qualquer projeto de software. Neste caso, no entanto, também se aplica à remoção de qualquer duplicação entre o código de teste e código de produção; e

Repetir (Repeat): O processo deve ser reexecutado com um novo teste, repetindo o

ciclo para avançar com no desenvolvimento das funcionalidades. O tamanho dos passos entre escrita de teste, falha, codificação e refatoração deve ser sempre pequeno, algo entre 1 a 10 edições para cada execução de teste. Se o novo código não satisfaz rapidamente um novo teste, ou outros testes falham inesperadamente, o desenvolvedor deve desfazer ou reverter a alteração do código, em vez de debugar o código. Para isso, é fundamental a execução de integração contínua entre as funcionalidades do sistema, fornecendo pontos de verificação – checkpoints – reversíveis.

Figura 24 – Sequência do fluxo do processo TDD

Fonte: Beck (2000, apud Pereira (2014).