1. Refatoração e TDD, feitos um para o outro

O processo de Refatoração depende substancialmente da existência de testes de unidade e aceitação. Sem estes testes, fica muito difícil ter a segurança de que a refatoração foi feita corretamente, ou seja, não modificou o comportamento (funcionalidade) do código, nem inseriu qualquer tipo de erro num código que anteriormente estava funcionalmente correto.

A Refatoração e a TDD são conceitos intimamente relacionados, ou seja, são dependentes e não funcionam de forma ótima, um sem o outro.

TDD pode ser utilizado sem refatoração, mas neste caso torna-se muito difícil fazer algo de qualidade (correto). Isto acontece porque com TDD codifica-se primeiro algo muito simples, apenas o suficiente para passar nos testes previamente escritos. Depois disso, melhora-se o código até que este fique com a qualidade mínima desejada, e a melhor maneira de melhorar um código que está funcionando é via refatoração.

Refatoração pode ser utilizada sem TDD, mas neste caso há uma grande possibilidade de ocorrerem problemas. Os testes expõem claramente quais as funcionalidades, facilitando o trabalho de mudar a implementação sem alterar o comportamento. Os testes também funcionam como um sistema de monitoramente bastante eficiente, já que alertam quando e onde um erro foi introduzido. Mesmo quando existe a intenção de escrever os testes, mas não como no TDD, ou seja, deixa-se para escrevê-los depois de implementar as funcionalidades, não se está agindo da melhor forma. Primeiro porque é muito comum esquecer de escrever algum dos testes, segundo porque também é comum neste caso, escrever vários testes desnecessários.

Existe o argumento de que essa fortíssima dependência da refatoração em relação aos testes não existe, pois a refatoração foi formalmente definida antes que o conceito de TDD fosse formalizado.

Realmente, a refatoração é mais antiga que a TDD. O primeiro trabalho detalhado e formal sobre refatoração, foi a tese de doutorado de William Opdyke [OPDYKE], publicada em 1993. Já a TDD só alcança um patamar mais formal em meados de 2000, o que torna a refatoração formal e correta antes mesmo da TDD existir.

A grande falha do argumento acima é que TDD é uma forma disciplina de desenvolver software claro e que funciona, baseada fundamentalmente em testes automatizados. Porém os testes sempre existiram, não surgiram com a computação e muito menos com a TDD.

Aplicar refatoração de forma disciplinada, em pequenos passos, seguindo corretamente os bons catálogos, garante altos ganhos e pequenas possibilidades de erros.

Porém essas pequenas possibilidades de erros, que são menores que as do desenvolvimento / manutenção sem refatoração, existem e não devem ser ignoradas. Por isso a dependência em relação aos testes automatizados e conseqüentemente, caso deseje-se algo mais robusto, em relação a TDD.

A conclusão é que, do ponto de vista da refatoração, usar TDD em um projeto, além de totalmente compatível, é algo lindo, uma verdadeira maravilha ;D, pois torna o desenvolvimento / manutenção ainda mais fácil, confiável e eficiente. E o melhor é que a recíproca também é verdadeira, ou seja, aplicar TDD auxiliada pela refatoração a um sistema é ótimo.

Parece que foram feitos um para o outro, pois formam um casal praticamente perfeito. Tanto refatoração quanto a TDD gostam de código claro (limpo, fácil de entender e manter) e que funciona. TDD luta de todas as formas para garantir que o código funcionará sempre e a refatoração usa todas as suas forças por um código cada vez mais claro, limpo, bonito. Resumindo, TDD garante a funcionalidade continua e a refatoração garante a clareza. E todos ficam felizes para sempre. :)


2. Refatoração

É o processo de alteração de um sistema de software de modo que o comportamento observável do código não mude, mas que sua estrutura interna seja melhorada. É uma maneira disciplinada de aperfeiçoar o código que minimiza a chance de introdução de falhas. Em essência, refatorar é melhorar o projeto do código após este ter sido escrito. [Fowler, Refatoracão]

Tornar o código mais fácil de entender e modificar, estes são os objetivos diretos da refatoração. Qualquer alteração no código que não vise estes objetivos, não pode ser considerada uma refatoração.

Ao programar, podemos ter código que funciona corretamente, mas que é difícil de entender por uma deficiência qualquer. A refatoração deve necessariamente ajudar a tornar o código mais legível, corrigindo deficiências estruturais, por exemplo.

As técnicas de refatoração incluem, entre outras coisas, metodologias para detectar (“farejar”) possíveis problemas no código.


Vantagens Indiretas da Refatoração

A refatoração acaba trazendo outros benefícios, que podem ser considerados indiretos, porque derivam da busca por um código mais fácil de entender e modificar.

:: Projetos Concluídos

Neste caso, a refatoração faz bem para o projeto de duas formas:

1. Melhorando de forma significativa um projeto mal elaborado. Ou seja, ao refatorar continuamente um projeto é possível corrigir problemas graves em sistemas já prontos, caso estes existam. Esta característica contraria uma máxima do desenvolvimento tradicional que diz ser praticamente inviável, do ponto do vista do custo / benefício, corrigir problemas de projeto em softwares concluídos.

2. Impedindo que o projeto se deteriore com as possíveis alterações que tendem a ocorrer ao longo do tempo.

 

:: Projetos em Implementação

Neste caso, a refatoração impede que os problemas presentes no projeto sejam codificados, ou seja, conhecendo-se as técnicas de refatoração, pode-se encontrar e corrigir os possíveis problemas de um projeto durante a própria implementação deste.

 

É claro que quanto pior estiver o projeto, maior a quantidade de refatorações necessárias para torná-lo fácil de entender e modificar. Ou seja, um projeto bem feito só trás benefícios, mas mesmo nos casos em que o projeto é ruim, refatorar continuamente permite detectar e corrigir muitos dos problemas presentes.

 

:: Aprendizado

Refatorar ajuda a tornar mais fácil a tarefa bastante comum de analisar e entender código legado. É possível através da refatoração, progressivamente ir tornando mais claros e fáceis de entender os trechos de código de um sistema legado, à medida que estes forem sendo analisados e entendidos. Nesse processo, é preciso investir intensamente no aprendizado do que o código realmente faz e aplicar este aprendizado no próprio código, através da própria refatoração.

Ou seja, a refatoração permite documentar de forma incremental e através do próprio código, o aprendizado das funcionalidades de um sistema.

Num nível mais alto, a refatoração permite aprender também sobre a estrutura do projeto, já que à medida que trechos de código vão sendo entendidos, fica muito mais fácil entender o projeto como um todo.

 

:: Depuração

Refatorar ajuda na melhora e no entendimento do código, conseqüentemente também ajuda no processo de depuração, pois é muito mais rápido e fácil encontrar uma falha num código claro e fácil de entender.

 

:: Velocidade

Refatorar torna mais rápido desenvolver software por todos os motivos explicados acima. Quando temos código e projeto:

· Mais claros e fáceis de entender;

· Com maior nível de conhecimento pelos desenvolvedores;

· Com menos falhas.

Conseqüentemente teremos maior velocidade de desenvolvimento e manutenção, e é claro, menores custos.

3. Desenvolvimento Dirigido por Testes

Código limpo que funciona (ou “Clean code that Works”), foi para alcançar este objetivo que o TDD surgiu. Um código será tanto mais limpo quanto melhor for seu design.

Uma forma de sempre ter código limpo que funciona, é utilizar o desenvolvimento fortemente guiado por testes automatizados que são escritos antes do código. Este estilo de desenvolvimento foi chamado de Desenvolvimento Guiado por Testes ou Test-Driven Development (TDD).

TDD é uma forma disciplinada de escrever código limpo que funciona, e consiste de duas regras principais:

· Código novo só é escrito se um teste automatizado falhar;

· Todas as duplicações devem ser eliminadas.

São duas regras simples, mas que tem conseqüências complexas no comportamento individual e coletivo dos desenvolvedores. As implicações técnicas são as seguintes:

1. Desenvolvimento orgânico, onde código em execução gera o retorno necessário para a tomar as decisões que orientam o próprio desenvolvimento;

2. Cada desenvolvedor deve escrever seus testes;

3. O ambiente de desenvolvimento deve fornecer respostas rápidas para pequenas mudanças;

4. O projeto deve ter alta coesão, componentes fracamente acoplados, exatamente para permitir testar facilmente

As duas regras também implicam numa ordem para as tarefas de programação

1. Vermelho – Escreva um pequeno teste que não passa, e provavelmente até mesmo não compila na primeira vez;

2. Verde – Faça o teste passar rapidamente, cometendo qualquer pecado que seja necessário durante o processo;

3. Refatore – Torne o código mais fácil de entender e modificar. Pode-se começar eliminando todas as duplicações criadas meramente para fazer o teste passar, por exemplo.

Vermelho / verde / refatore — O mantra do TDD”.


Porque usar TDD

- Aprendizado

Quanto maior for o tempo entre a inserção de um erro no código e sua descoberta pelo desenvolvedor, maior será a probabilidade deste erro repetir-se em outros locais do sistema e menor a possibilidade de aprendizado. Por outro lado, se o erro é descoberto alguns segundos após ser introduzido, maiores a chances do desenvolvedor corrigi-lo rapidamente, aprender com isto e passar a codificar melhor, conseqüentemente reduz-se muito as chances de problemas semelhantes repetirem-se no futuro. Para um melhor aprendizado e redução da probabilidade de propagação de erros, é fundamental que o ambiente de desenvolvimento forneça respostas rápidas para pequenas mudanças

 

- Redução dos custos e vulnerabilidades do sistema

Escrever os testes antes, da forma que prega o TDD, equivale a prevenir-se de problemas futuros. As fases de desenvolvimento e depuração ocupam a maior parte do tempo de um projeto, sendo que a depuração geralmente só é feita quando o software apresenta um ou mais erros (Bugs). O que torna a depuração muito custosa é o tempo entre a inserção do bug e o momento em que este é detectado. Quanto maior o tempo, maior o custo de depuração, porque para corrigir um problema, o desenvolvedor precisa recuperar o contexto em que este foi inserido, entender uma série de coisas relacionadas, além de descobrir o que pode estar gerando o erro. Ou seja, é preciso re-aprender sobre a funcionalidade para que se possa corrigi-la.

Devido a grande complexidade envolvida no processo de desenvolvimento de software é comum ocorrerem erros dos mais variados tipos. É impossível evitar que estes erros ocorram ao longo de um projeto, entretanto é possível fazer alguma coisa em relação à quando estes defeitos são detectados e qual o impacto que causarão no cronograma do projeto. Só isto, causa um grande impacto na velocidade de desenvolvimento e na qualidade do software.

O desenvolvimento dirigido por testes segue o caminho da prevenção. Para isso é preciso incorporar hábitos que resultem numa menor probabilidade de ocorrência de erros. Mesmo assim, é possível que erros ocorram. Neste caso, os testes fazem com que a correção do erro seja mais barata por dois motivos:

· O teste expõe o erro assim que ele entra no sistema, o que evita muita perda de tempo com depurações demoradas.

· Caso um erro seja introduzido em uma parte do sistema diferente da que se está trabalhando no momento, os testes expõem o erro, mostrando precisamente onde ele se encontra e assim permitindo que este seja corrigido rapidamente.

 

- Aumento da qualidade e produtividade

Sempre que um teste detecta uma falha rapidamente, evitam-se longas sessões de depuração que costumam tomar boa parte do tempo dos projetos. Com mais tempo disponível e melhores oportunidades de aprendizado, os desenvolvedores codificam mais rapidamente e com maior qualidade, ou seja, aumenta-se a produtividade e reduz-se a incidência de defeitos (“Clean code that works”, [BECK, 2002]).


[BECK, 2002]
[FOWLER, 2004]
[HUNT, 2004]
[TELES, 2004]