Artigo no estilo Mentoring
Refatoração é o processo de modificar um sistema de software sem alterar o comportamento externo do código, melhorando sua estrutura interna. É uma forma disciplinada de limpar minimizando as chances de introduzir erros. Quando se refatora está se melhorando o design do código depois de ele ter sido feito. Primeiro um bom projeto deveria ser feito, a seguir a sua codificação, mas nem sempre é assim que as coisas acontecem.
Com a evolução do sistema de software, mudanças ocorrerão, e a sua estrutura e integridade original diminuem. Dessa forma, essas transformações, no caso as refatorações, podem melhorar a estrutura do projeto. Embora a reestruturação crie novas versões que implementam ou propõem mudanças no objetivo final do sistema, normalmente não envolvem modificações referentes a novos requisitos, ou seja, não visam implementar novas funcionalidades no sistema de software. No entanto, podem conduzir a observar melhor o objetivo do sistema, já que sugerem mudanças que poderem melhorar sua estrutura interna.
Nesse sentido, é necessário identificar locais no código ou outros artefatos que precisam ter sua estrutura modificada, seja para melhorar sua legibilidade, melhorar o projeto, tornar mais simples de evoluir e de manter. Tais estruturas passíveis de refatoração são também conhecidas como “bad smells”, ou problemas (shortcomings). Um bad smell sugere que existem deficiências que podem ser sanadas ou melhoradas, porém é necessário que a aplicação continue apresentando o mesmo comportamento externo após a transformação interna.
Outro ponto a ser considerado no estudo da refatoração é o uso de Padrões de Projeto, ou Design Patterns, amplamente utilizados no projeto de arquiteturas de software, pois representam soluções gerais, reutilizáveis, testadas e documentadas, resolvendo problemas recorrentes de programação orientada a objetos. Muitas vezes, no entanto, padrões de projeto tendem a ser utilizados de forma antecipada em um projeto.
Já com refatoração, você parte de um mau design (muitas vezes do caos absoluto), refatora e obtém um código bem projetado. Cada refatoração consiste de um passo simples, pequeno. Você move um campo para outra classe, move um método para uma classe superior na hierarquia, extrai uma classe nova a partir de outra existente etc. Cada pequeno passo vai melhorando de forma incrementa o design do código como um todo.
Existem várias motivações para o uso de refatorações. Elas tornam mais fácil a adição de novo código. Quando se inclui uma nova funcionalidade em um sistema de software, pode-se programar sem se preocupar o quão bem se encaixa no projeto existente, ou pode modificar o projeto existente a fim de melhor implementar a funcionalidade.
No primeiro caso, ocorre um débito de projeto, o qual pode ser resolvido mais tarde com refatoração. Além disso, as refatorações melhoraram um projeto de código existente, no momento que tornam o código mais simples, claro e mais fácil de trabalhar, manter e evoluir. A refatoração contínua envolve procurar constantemente por problemas e removê-los imediatamente. E finalmente, refatorações ajudam a se obter um melhor entendimento do código. Se um código está difícil de ser compreendido, programadores normalmente comentam este código para tornar mais clara sua intenção. Se o código não está claro, o problema precisa ser removido através de refatoração.
Refatoração é uma atividade vital em abordagens ágeis de desenvolvimento. Uma transformação na estrutura pode ser frequentemente relacionada à sua aparência (por exemplo, melhorar a legibilidade), mas pode ser uma alteração no design da aplicação.
Refatorações podem melhorar a qualidade de um software, por exemplo, extensibilidade, modularidade, maior reutilização de código, menor complexidade, manutenção mais fácil, eficiência etc. Podemos dividir as refatorações em duas grandes categorias, as primitivas e as formados por composição. Há ainda refatorações mais complexas, as compostas que tem como resultado da transformação a aplicação de um Padrão de Projeto (Design Pattern).
Uma refatoração primitiva seria, por exemplo, renomear um objeto, mover um método etc. As refatorações mais complexas são normalmente obtidas pela composição de várias primitivas. O processo de refatoração consiste em uma série de atividades distintas, incluindo: identificar onde um software precisa ser refatorado, determinar qual refatoração pode ser aplicada, garantir que o comportamento se mantém, aplicar a refatoração, medir o impacto do refactoring nas características do software, como complexidade, usabilidade, custo, esforço etc.
Manter a consistência entre o código refatorado e outros artefatos do sistema, como diagramas UML, documentação em HTML, PDF, especificação de requisitos, testes etc. Identificar bad smells no código para criar oportunidades de refatoração é uma técnica bastante interessante e difundida atualmente. De acordo com Kent Beck, bad smells (“maus cheiros”) são estruturas no código que sugerem a possibilidade de refatoração. Alguns exemplos de problemas em estruturas de código são: código duplicado, métodos longos, classes longas, métodos com muitos parâmetros, entre outros.
Podemos usar métricas de software para, por exemplo, identificar falhas no design de um software que apresenta classes de um framework com um alto grau de acoplamento, reduzindo assim o reaproveitamento. Neste caso, poderia se usar refatoração para padrões de projeto, a fim de melhorar o design. Testes ou gráficos de dependência podem ajudar a medir a eficiência dos refactorings.
Outro ponto importante a ser considerado são as pré e pós condições das atividades de refatoração. Por exemplo, uma pré-condição de um sistema de tempo real, como uma aplicação Web de E-Commerce, é o tempo de resposta ao usuário. De nada adianta melhorar a legibilidade do código e design se ao final tivermos uma queda no tempo de resposta, pois nesse caso, performance é uma pré-condição.
O mesmo vale para sistemas embarcados, por exemplo, aplicações que rodam em smartphones, elas precisam consumir pouca memória e bateria, outra pré-condição.
Antes de entrarmos em um estudo de caso, vamos fazer uma análise da refatoração dentro do contexto de desenvolvimento Delphi, rebuscando a história das linguagens RAD. Antes do surgimento do Delphi 1, que foi um marco para o desenvolvimento visual na época, tínhamos apenas o Visual Basic como forte concorrente.
Foi exatamente nesta época que surgiu o conceito de “desenvolvimento visual”, ou as “linguagens visuais”, incluindo aí o então IDE do Visual Studio a seguir. O termo “visual” se originou do fato de que as linguagens de programação não tinham um ambiente gráfico de design, basicamente você programava num editor de textos “às escuras”, compilava, rodava e torcia para que os elementos gráficos ficassem organizados como previsto no código.
Assim era feito em ambientes como o Turbo Pascal e o Turbo C, e começou a mudar com a introdução do Turbo Vision, o tataravô do Delphi. Esse “apelo” trazido pelas linguagens visuais, como Delphi e VB, tornaram o desenvolvimento extremamente rápido, muito rápido. Aquela barra de menu que se levava duas semanas para construir estava ali pronta na caixa de ferramentas, basta fazer o “drag & drop” e pronto. Antes mesmo de compilar, você já tem o visual da interface de usuário.
Esse desenvolvimento rápido introduziu outro termo amplamente utilizado até hoje, o RAD – Rapid Application Development, o desenvolvimento rápido de aplicações. Aqui entra o fator crítico e o elo dos “studios” (RAD, Visual etc.) com a Refatoração: a programação seguindo esta abordagem RAD permite que muitos desenvolvedores abram mão de boas práticas de orientação a objetos e padrões de projeto para obter um mesmo resultado mais rapidamente, seja por falta de conhecimento, pressão devido a prazos curtos ou mesmo para reduzir custos abrindo mão da qualidade.
O sistema parece funcionar bem por fora, mas por dentro está mal projetado, ou não tem projeto, ou está um verdadeiro caos que nem mesmo o programador original o entende. Todo o código está em um único formulário ou data module. Não existem classes de negócio, e as poucas que existem estão fortemente acopladas.
Conforme a aplicação cresce, mais componentes, código e funcionalidades (e bugs, muitos deles) são adicionados ao projeto original. Para muitas empresas, se não a maioria delas (exceto startups), o foco principal ...