Atenção: esse artigo tem uma palestra complementar. Clique e assista!

Atenção: esse artigo tem um vídeo complementar. Clique e assista!

Do que trata o artigo

Refactoring trata-se de um processo que tem como principais objetivos tornar o código mais legível e com maior manutenibilidade. Menciona-se processo, pois refactoring não consiste em apenas mudar o código que já funciona, pois quando há qualquer tipo de alteração, há riscos de introdução de novos bugs. Refactoring é algo maior, que envolve pequenos passos, testes, disciplina e força de vontade. Este artigo irá demonstrar de forma pragmática como um processo de refactoring deve ser conduzido.

Para que serve

Serve para melhorar evolutivamente o código através de pequenas incursões, sejam em novas aplicações ou durante a manutenção corretiva e evolutiva das existentes. Parte-se da premissa que não realizaremos o melhor design da primeira vez que um código é escrito. Algumas melhorias nem sequer a vemos durante o desenvolvimento da aplicação, mas sim após o melhor entendimento de um problema que estamos submetidos.

Em que situação o tema é útil

Refactoring é uma ferramenta sem custo e útil o tempo todo, pois é um processo simples, fácil de ser seguido e com resultados comprovados em curto prazo. Assim como um diamante bruto após processo de lapidação torna-se uma jóia límpida e com formas vistosas, o refactoring lapida o software, tornando-o simples e legível, que são pilares para que a manutenção seja conduzida de uma forma menos dolorosa e com menor custo.

Resumo do DevMan

Refactoring é um processo de alterações simples e sistemáticas que são feitas no código. As alterações serão apoiadas por um conjunto de testes automatizados e consistentes que garantirão que cada funcionalidade produza o mesmo comportamento que tinha antes do refactoring. A ideia do refactoring é que a alteração interna do código não altere o comportamento observado pelos elementos externos ao sistema. Você aprenderá qual é este processo e como você irá conduzí-lo. O paradigma: “no que está funcionando não se mexe” será quebrado e você estará seguro disto. Não terá vergonha que alguém veja seu código e o critique, pois ele será simples e legível.

Vale a ilustríssima frase de Martin Fowler: “Any fool can write code that a computer can understand. Good programmers write code that humans can undertand”, que em tradução livre significa algo como “Qualquer tolo pode escrever código que um computador entenda. Bons programadores escrevem códigos que humanos possam entender”.

Refactoring é utilizado por pessoas comuns, assim como você e eu, pois gênios não erram e não precisam de tais recursos. Se você for um gênio, por favor, pare por aqui. Caso não, aproveite a leitura e coloque o Refactoring em prática.

Martin Fowler, famoso engenheiro de software, no livro “Refactoring, Improving the Design of Existing Code”, define refactoring em dois contextos, os quais em tradução livre, reporto a seguir:

“Refactoring: alteração realizada na estrutura interna do software para torná-lo fácil de entender e barato para modificar, sem alterar o comportamento externo.

Refactor: reestruturar o software aplicando um conjunto de refatorações, sem alterar o comportamento externo.”

Acredito que o conceito tenha ficado claro, no entanto é interessante destacar os possíveis cenários nos quais a refatoração pode ser aplicada:

• Sistemas legados: Grande dor de cabeça da maioria dos desenvolvedores. A manutenção é sempre agressiva e desanimadora devido aos mais variados motivos: código duplicado, lógica de negócio duplicada, o fato do código já ter passado pela mão de dezenas de desenvolvedores, nomes de funções ou classes já não condizem com os reais objetivos, entre outros;

• Novos sistemas: Um pouco contraditório, não? Explico: No TDD, que no meu entendimento é uma técnica de design, temos os seguintes passos:

o Adicionar um teste;

o Executar o teste. Ele falhará;

o Escrever o código para o teste passar;

o Rodar novamente o teste. Ele passará;

o Refatorar o código;

o Repetir quantas vezes forem necessárias, até você atingir o design desejado.

No passo “Escrever o código para o teste passar”, temos como objetivo inicial atender a regra de negócio que o teste valida, portanto, não nos preocupamos com o design, de qualquer forma, temos a premissa do refactoring, o código existente. Com o código aderente a regra, ou seja, um comportamento desejável, refinamos o código(refactoring) e rodamos o teste novamente até que ele passe. Como resultado, temos o código melhorado e com o mesmo comportamento.

Para entendendermos o processo de refactoring, vamos a um exemplo prático.

Nota do DevMan

TDD, ou Test-Driven Development, é uma das práticas do XP (Extreme Programming). Basicamente, a ideia é que primeiro sejam desenvolvidos os testes para só então escrever o código necessário para que o teste passe. Com os testes devidamente criados, temos a segurança necessária para então refatorar o código com a segurança que os testes promovem de que não quebraremos nenhuma funcionalidade.

Melhorando o design de uma aplicação real

Para o exemplo, vou utilizar o módulo de um sistema que eu mesmo fiz há alguns anos e que tornou-se complicado de manter. O objetivo do módulo é efetuar a carga de cotações históricas de ações da Bovespa, disponibilizada através de um arquivo texto posicional. A mecânica deste módulo funciona da seguinte forma:

• Usuário entra no site da Bovespa, loga-se e baixa o arquivo de cotações históricas. Ele pode selecionar, por exemplo, as cotações do dia anterior. O arquivo é baixado no formato .zip;

• Usuário loga-se no sistema e realiza o upload do arquivo de cotações;

• Uma aplicação .NET 2.0 do tipo Windows Service fica monitorando um diretório (que foi parametrizado em arquivo de configuração) e, quando um arquivo com a extensão .zip é detectado, o serviço abre, descompacta e disponibiliza o arquivo .TXT que estava dentro do zip;

• Sistema interpreta o arquivo conforme o layout da Bovespa e grava em banco de dados as cotações.

A solução está distribuída em quatro assemblies, como mostra a Figura 1. Na Figura 2 temos o diagrama de classes.

Figura 1. Diagrama de componentes da solução atual

Figura 2. Diagrama de classes da solução

Antes de iniciarmos o refactoring utilizando o Visual Studio 2008 Team Suite, vamos coletar as métricas do código da solução atual. Para capturar as métricas, clique com o botão direito sobre cada projeto e selecione a opção “Calculate Code Metrics”. Após o refactoring, vamos rodar novamente e avaliar os resultados. A Figura 3 mostra a análise inicial.

Figura 3. Métricas de código

Nota: As métricas de código ajudam o desenvolvedor a avaliar a complexidade, reuso, padronização e outras características do sistema.

O refactoring para este artigo será realizado nas classes BO.Cotacao, BE.Cotacao e DAL.Cotacao. A aplicação atual não tem nenhum teste automatizado, me deixando inseguro para iniciar qualquer tipo de incursão no código pois, afinal, esta é uma aplicação que já funciona.

No Listagem 1 temos o trecho de código do Windows Services que inicia o processo de importação.

Listagem 1. Trecho de código onde o processamento é iniciado

  // Define the event handlers.
          private static void OnChanged(object source, FileSystemEventArgs e)
          {
              try
              {
                  EventLog.WriteEntry("AMAWEB", "Início da carga do arquivo " + e.FullPath + " !", EventLogEntryType.Information);                    
                  Cotacoes objCotacoes = new Cotacoes();
                  objCotacoes.ImportarArquivoCotacoesBovespa(e.FullPath);
                  EventLog.WriteEntry("AMAWEB", "Carga do arquivo " + e.FullPath + " realizada com sucesso!", EventLogEntryType.Information);                    
              }
              catch (Exception err)
              {
                      EventLog.WriteEntry("AMAWEB", "Erro ao processar o arquivo de cotações " + e.FullPath + ". Erro: "+ err.Message +"\n Pilha:" + err.StackTrace + "Fonte:" + err.Source, EventLogEntryType.Error);
              }
          } 
...

Quer ler esse conteúdo completo? Tenha acesso completo