BT
x A sua opinião é importante! Por favor preencha a pesquisa do InfoQ sobre os seus hábitos de leitura!

Esclarecendo os Equívocos Mais Comuns Sobre Refatoração

Postado por Danijel Arsenovski , traduzido por Vinicius Assef em 18 Jun 2009 |

É justo dizer que na comunidade .Net a refatoração teve um início lento. Mesmo hoje, o Visual Studio, um produto clássico para o desenvolvimento em .Net tem dificuldade de atravessar a Fronteira da Refatoração com o C#. Com o Visual Basic, ou mais recentemente com o C++, a situação está melhor, mas só se você fizer o download e instalar o add-in gratuito de refatoração, Refactor! para VB ou C++, desenvolvido pela Developer Express.

Além dessa, todas as outras alternativas são produtos pagos. Mesmo que eles valham cada centavo investido, e conhecendo a rotina de compras de uma empresa quando aparecem argumentos estranhos e não essenciais como "qualidade do código", passará muito tempo até os desenvolvedores possam usá-los. É claro que você pode refatorar sem uma ferramenta, mas o processo manual pode ser árduo e sem nenhum atrativo. Não há dúvidas que a comunidade .Net está ficando para trás na adoção da refatoração e que ainda há muita confusão sobre ela e sobre sua utilidade.

Nesse artigo, eu tentei listar alguns equívocos que vejo com maior frequência. Estes, junto com outras pré-concepções a respeito da programação, podem apresentar um problema sério no processo de adoção dessa técnica tão valiosa. Em seguida, apresentarei esses obstáculos e tentarei explicar suas origens e dar bons argumentos para refutá-los. Espero que possa ser útil para alguém que ainda tem alguma dúvida a respeito da verdadeira natureza da refatoração, ou para alguém que esteja aprendendo a refatorar, ou que esteja se empenhando em estabelecer e disseminar essa prática em sua equipe.

"Se Não Estiver Quebrado, Não Conserte"

Frequentemente identificada como uma sabedoria da engenharia, a postura do "se não estiver quebrado, não conserte" só promove a complacência. A refatoração trabalha contra ela, e por uma boa razão.

Bem cedo, em sua vida de programador, você aprende que mesmo o menor detalhe no código pode fazer uma enorme diferença, muitas vezes valendo muito ter esse conhecimento. Uma mudança pequena pode provocar um erro no software de uma maneira surpreendente, e na pior das situações. Portanto, já que você tem que "sujar as mãos", é possível que você relute em fazer qualquer mudança que não for absolutamente necessária. Isso pode funcionar bem por um tempo. Entretanto, é inevitável que os bugs sejam corrigidos e que as solicitações de novas funcionalidades não possam mais ser adiadas. Então, você estará frente a frente com o mesmo código que tentou tanto evitar.

Aqueles que adotam a postura do "se não estiver quebrado, não conserte" olham para a refatoração como intruso desnecessário que vem com alguma coisa que eles já têm. Na verdade, essa postura conformista que tenta manter o "status quo" é o resultado de tentar racionalizar o medo de enfrentar o código e o fato de que não têm controle sobre ele.

Muitos programadores experientes adotam essa postura por causa da intenção de eliminar qualquer esforço que não seja realmente necessário. Por exemplo, se a aplicação está com um bom desemepnho, então não há necessidade de espremer aquele último ciclo de cpu para melhorá-la. De modo parecido, está o projeto especulativo, reconhecido pela seguinte frase profética: "nós poderíamos ter essa funcionalidade um dia".

Nesse sentido, a refatoração está na mesma linha de pensamento. Quando você refatora, deveria eliminar todo código morto, evitar o projeto especulativo ou a otimização prematura.

Entretanto, para os adeptos da refatoração, o software também pode estar quebrado "por dentro". Se o projeto é falho e o código é ruim e mal estruturado, então mesmo que a aplicação esteja atendendo corretamente aos usuários, e não está quebrada "por fora", ela deveria ser refatorada e o projeto "consertado". Nesse sentido, a refatoração insiste em algumas características do software que são menos tangíveis, mas decisivas, como projeto, simplicidade, melhoria na compreensão do código fonte e legibilidade, dentre outras.

A refatoração ajudará a você ter novamente o controle sobre seu código. Enquanto essa tarefa é muito difícil de realizar em um código que cresceu fora de controle, em a refatoração a única solução que pode ser considerada é a re-escrita completa do código.

Refatoração Não É Nada Novo

Esse equívoco poderia ser colocado como "Refatoração é apenas outra palavra para uma coisa que todos nós já sabemos". O que significa que todos vocês já aprenderam sobre bons códigos, projeto orientado a objetos, estilo, boas práticas, etc., e refatoração é apenas mais uma palavra do momento que alguém inventou para vender livros.

Está certo, a refatoração não pretende inserir radicalmente novos paradigmas como programação orientada a objetos ou a aspectos quando elas apareceram pela primeira vez. O que ela faz radicalmente é mudar a maneira que você programa: ela define regras que permitem fazer mudanças complexas no código com o clique de um botão. Você não olha para seu código como uma construção congelada que não é suscetível a mudanças. Pelo contrário, você se vê na condição de manter seu código em ótima forma, respondendo eficientemente aos novos desafios e modificando o código sem nenhum medo.

Refatoração É Muito Difícil

Programar é difícil. É uma atividade complexa que requer muito esforço intelectual. Alguns conhecimentos dessa área podem ser muito difíceis de dominar. Com Visual Basic .NET, os programadores em VB tiveram que adquirir a habilidade de trabalhar em uma linguagem completamente capaz de lidar com orientação a objetos. Para muitos, isso foi intimidador no início. A boa notícia é que essa nova habilidade realmente ajuda muito.

A grande vantagem da refatoraão é o quão simples ela pode ser. Você é equipado com um pequeno conjunto de regras para iniciar. Isso, junto com uma boa ferramenta, tornam os primeiros passos na refatoração muito tranquilos. Comparada com outras técnicas que um programador avançado deve conhecer hoje em dia, como UML ou design patterns, eu diria que a refatoração tem a menor curva de aprendizado, bem parecido como é o VB comparado com outras linguagens.

Bem cedo, o tempo investido em aprender refatoração vai começar a dar frutos. É claro que, como qualquer outra coisa na vida, dominar o assunto requer tempo e esforço.

Refatoração Causa Mal Desempenho

Uma forma mais detalhada de dizer isso seria "Devido ao fato de depois de refatorar você normalmente termina com um número maior de elementos como métodos e classes, o novo projeto com tanta coisa vai exigir seu preço no desempenho".

Se você voltar um pouco no tempo, descobrirá que esse argumento soa curiosamente parecido com o que foi usado no início da programação orientada a objetos, pelos céticos.

A verdade é que as diferenças em desempenho entre os códigos refatorados e os desestruturados são mínimas. Exceto em alguns sistemas muito especializados, esse não é um problema real.

A experiência mostra que os gargalos de desempenho são geralmente afetados por alguns pontos específicos no código. Corrigir esses pontos na fase de otimização lhe dará os níveis desejados de desempenho. Ser capaz de identificar facilmente as peças críticas de código pode mostrar-se muito valioso. A refatoração ajuda muito no processo de otimização, produzindo código inteligível onde não há duplicação, o tamanho total é diminuído e as mudanças podem ser realizadas em um único local.

Atualmente, quando a potência das CPUs aumenta constantemente, alguns outros aspectos do código como facilidade na manutenção, qualidade, escalabilidade e disponibilidade estão fazendo com que o desempenho não seja mais a maior preocupação na lista de prioridades. Agora, não use isso como pretexto para escrever programas lerdos. Não exagere!

No casode você querer ver alguns números aqui, eu preparei uma pequena experiência. Vou usar dois códigos simples. O primeiro é um exemplo de um código mal estruturado que tem um único método Main. O segundo exemplo tem um método Main dentro de um Module e uma classe Circle com vários métodos pequenos. Originalmente eu usei esses exemplos para demonstrar a diferença entre os estilos de código estruturados x desestruturados, portanto ele não exato apenas em alguma medição de código.

Eu vou medir o tempo que ele leva para executar uma fórmula geométrica simples (o tamanho da circunferência de um círculo) e para não direcionar essa medição para um código que faz apenas cálculos, vou adicionar alguns acessos ao banco de dados. Para ter uma noção mais real do tempo gasto, vou repetir a execução em um loop por 10.000 vezes. Já que não preciso ser tão exato na minha medição, vou usar a classe System.Diagnostics.Stopwatch para capturar o intervalo de tempo. A precisão do Stopwatch será suficiente nesse caso.

Código de exemplo 1: Código desestruturado

 Option Explicit On
 Option Strict On

 Imports System.Diagnostics
Imports System.Data.SqlClient

 Namespace RefactoringInVb.Chapter9 

     Structure Point
         Public X As Double
         Public Y As Double
     End Structure

     Module CircleCircumferenceLength

         Sub Main()
             Dim center As Point
             Dim pointOnCircumference As Point
             'read center coordinates
             Console.WriteLine("Enter X coordinate" + _
             "of circle center")
             center.X = CDbl(Console.In.ReadLine())
             Console.WriteLine("Enter X coordinate" + _
             "of circle center")
             center.Y = CDbl(Console.In.ReadLine())
             'read some point on circumference coordinates
             Console.WriteLine("Enter X coordinate" + _
             "of some point on circumference")
             pointOnCircumference.X = CDbl(Console.In.ReadLine())
             Console.WriteLine("Enter X coordinate" + _
             "of some point on circumference")
             pointOnCircumference.Y = CDbl(Console.In.ReadLine())
             'calculate and display the length of circumference
             Console.WriteLine("The lenght of circle" + _
             "circumference is:")
             'calculate the length of circumference
             Dim radius As Double
             Dim lengthOfCircumference As Double
             Dim i As Integer
             'use stopWatch to measure transcurred time
             Dim stopWatch As New Stopwatch()
             stopWatch.Start()
             'repeat calculation for more precise measurement
             For i = 1 To 10000
                 'add some IO
                 Dim connection As IDbConnection = New SqlConnection( _
                 "Data Source=TESLATEAM;" + _
                 "Initial Catalog=RENTAWHEELS;" + _
                 "User ID=RENTAWHEELS_LOGIN;" + _
                 "Password=RENTAWHEELS_PASSWORD_123")
                 connection.Open()
                 Dim command As IDbCommand = New SqlCommand( _
                 "SELECT GETDATE()")
                 command.Connection = connection
                 Dim reader As IDataReader = command.ExecuteReader()
                 reader.Read()
                 reader.Close()
                 connection.Close()
                 radius = ((pointOnCircumference.X - center.X) ^ 2 + _
                 (pointOnCircumference.Y - center.Y) ^ 2) ^ (1 / 2)
                 lengthOfCircumference = 2 * 3.1415 * radius
             Next
             stopWatch.Stop()
             Console.WriteLine(stopWatch.Elapsed)
             Console.WriteLine(lengthOfCircumference)
             Console.Read()
         End Sub
      End Module
  End Namespace

Código de exemplo 2: Código estruturado

Option Explicit On
 Option Strict On

 Imports System.Data.SqlClient

 Namespace RefactoringInVb.Chapter11
      Public Structure Point
         Public X As Double
         Public Y As Double
     End Structure

     Module CircleCircumferenceLength

         Sub Main()
             Dim circle As Circle = New Circle
             circle.Center = InputPoint("circle center")
             circle.PointOnCircumference = InputPoint( _
             "point on circumference")
             Console.WriteLine("The length of circle " + _
             "circumference is:")
             Dim circumference As Double
             Dim i As Integer
             'use stopWatch to measure transcurred time
             Dim stopWatch As New Stopwatch()
             stopWatch.Start()
             'repeat calculation for more precise measurement
             For i = 1 To 10000
                 circumference = circle.CalculateCircumferenceLength()
             Next
             stopWatch.Stop()
             Console.WriteLine(stopWatch.Elapsed)
             Console.WriteLine(circumference)
             WaitForUserToClose()
         End Sub

         Public Function InputPoint(ByVal pointName As String) As Point
             Dim point As Point
             Console.WriteLine("Enter X coordinate " + _
             "of " + pointName)
             point.X = CDbl(Console.In.ReadLine())
             Console.WriteLine("Enter Y coordinate " + _
             "of " + pointName)
             point.Y = CDbl(Console.In.ReadLine())
             Return point
         End Function

          Private Sub WaitForUserToClose()
             Console.Read()
         End Sub
      End Module
      Public Class Circle
         Private centerValue As Point
         Private pointOnCircumferenceValue As Point
         Public Property Center() As Point
             Get
                 Return centerValue
             End Get
             Set(ByVal value As Point)
                 centerValue = value
             End Set
         End Property
         Public Property PointOnCircumference() As Point
             Get
                 Return pointOnCircumferenceValue
             End Get
             Set(ByVal value As Point)
                 pointOnCircumferenceValue = value
             End Set
         End Property

         Public Function CalculateCircumferenceLength() As Double
             QueryDatabase()
             Return 2 * 3.1415 * CalculateRadius()
         End Function

         Private Function CalculateRadius() As Double
             Return ((Me.PointOnCircumference.X - Me.Center.X) ^ 2 + _
             (Me.PointOnCircumference.Y - Me.Center.Y) ^ 2) ^ (1 / 2)
         End Function

         Private Sub QueryDatabase()
             Dim connection As IDbConnection = New SqlConnection( _
                 "Data Source=TESLATEAM;" + _
                 "Initial Catalog=RENTAWHEELS;" + _
     "User ID=RENTAWHEELS_LOGIN;" + _ 
                 "Password=RENTAWHEELS_PASSWORD_123")
             connection.Open()
             Dim command As IDbCommand = New SqlCommand( _
 "SELECT GETDATE()")
             command.Connection = connection
             Dim reader As IDataReader = command.ExecuteReader()
             reader.Read()
             reader.Close()
             connection.Close()
         End Sub
     End Class
 End Namespace

Depois de algumas execuções, você pode conferir que as duas versões têm os tempos de execução muito próximos. No meu computador, eles estão entre 2,2 a 2,4 segundos. Um detalhe é que o melhor tempo para o código desestruturado foi de 1.9114800 e para o estruturado foi de 2.0398497. Na minha opinião não é uma diferença muito grande.

Refatoração Quebra Um Bom Projeto Orientado a Objetos

Um código bem estruturado e refatorado pode parecer estranho para um olho destreinado. Os métodos são tão pequenos que frequentemente parecem sem substância. As classes parecem sem o peso suficiente, consistindo de apenas poucos membros. Parece que nada acontece no seu código.

Ter que gerenciar mais elementos como classes e métodos pode parecer que há mais complexidade para administrar.

Esse argumento, na verdade é equivocado. A verdade é que essa mesma complexidade sempre esteve presente. Entretanto, no código refatorado, ela é expressa de um modo muito mais claro e mais estruturado.

Refatoração Não Oferece Benefícios de Curto Prazo

Existe um consenso incrível entre as pessoas que adotaram a refatoração: ela faz com que você programe mais rápido. Bem, não conheço nenhum estudo que eu poderia citar para provar o que eu disse, mas minha própria experiência diz que isso é verdade. É tão lógico, que é assim mesmo. Você tem uma quantidade menor de código, menos duplicação, e um quadro mais claro -- a menos que você esteja lidando com um código muito trivial e muitíssimo pequeno. Por isso os benefícios da refatoração aparecem bem rápido.

Refatoração Só Funciona para Equipes Ágeis

Pelo fato de ela ser bastante mencionada como um dos pilares das metodologias ágeis, a refatoração é vista como só funcionando em equipes que adotaram os princípios ágeis de trabalho.

Refatoração é indispensável para equipes ágeis.

Mesmo que sua equipe tenha uma metodologia diferente, na maior parte do tempo você é quem dita as regras de como escrever seu código, e aí é aonde a refatoração entra em cena.O fato de você entrar na opção "Refactor" de seu IDE, de vez em quando, pode passar desapercebido para os outros colegas de equipe ou mesmo para seu gerente. Deste modo, não há nada que impeça você de refatorar seu código, independentemente da metodologia seguida por sua equipe. Os melhores resultados na refatoração são alcançados se você adotá-la em passos pequenos, enquanto você escreve seu código. Algumas práticas, como propriedade estrita de código ou um processo em cascata podem jogar contra a refatoração. Se você conseguir provar que ela tem sentido sob o ponto de vista da programação, você pode começar construindo sua base de suporte, primeiro com seus colegas imediatos, depois espalhando a notícia para o restante da equipe.

A Refatoração pode ser aplicada como um estágio separado no processo de desenvolvimento e pode ser executada por uma equipe diferente

Essa aqui é geralmente favorecida pelos gerentes. Ser capaz de olhar para a refatoração como um estágio separado em algum lugar entre a implementação e a fase de testes, pode dar a falsa sensação de controle para o ponto de vista gerencial, onde as tarefas e os recursos são frequentemente vistos como barras em um gráfico Gantt, que podem ser facilmente espremidas e movidas para outro lugar.

A verdade é quepara executar a refatoração com sucesso, você deveria ter total entendimento do problema, estar ciente dos requisitos, do projeto e até mesmo dos detalhes de implementação. Se você não fez parte da equipe desde o começo, você não teve tempo com os clientes, não analisou os requisitos e não pensou sobre o projeto. Sendo assim, você vai ter muita dificuldade melhorando alguma coisa construída pela equipe original.

Seguir o modelo onde o código pode ser refinado a posteriori é similar a uma substância em um processo industrial que geralmente trará poucos benefícios. Sem um bom entendimento sobre o que o código realmente faz, se você refatorá-lo com bastante segurança, terá pouquíssimos benefícios. Se você tentar implementar alguma mudança substancial nele, os resultados podem ser exatamente o contrário do que você desejava. Ao invés de fazer com que o código atenda melhor ao objetivo original, provavelmente você introduzirá bugs na aplicação, tornando as coisas ainda piores.

Refatoração pode funcionar bem, mesmo sem testes unitários

Eu imagino que algumas refatorações simples podem ser feitas mesmo sem os testes unitários. As ferramentas de refatoração e até o compilador podem lhe proporcionar uma rede básica de proteção que você pode usar para encontrar alguns erros simples. Você também pode testar o código da maneira tradicional, usando um debugger ou realizando testes funcionais. Estes testes manuais podem ser maçantes e inadequados. E com a refatoração, seu código está mais propenso a mudar do que nunca. Evite problemas desnecessários, acrescente alguns testes do NUnit ao seu projeto e você estará apto a garantir seu código a cada pequeno passo que você der.

Não basear-se nos comentários não pode estar certo

Garantia de produzir aqueles cenários divertidos de confusão e descrença. Estou certo que você ouviu várias vezes que tem que escrever comentários em seu código. Esta prática é considerada boa, que ajudará às outras pessoas a entenderem seu código. Ela é interpretada como um sinal de uma abordagem boa, sistemática e profissional na codificação de programas. Portanto, se agora alguém ousa dizer que os comentários não são uma boa idéia, isso deve trazer uma certa surpresa.

Frequentemente, a motivação para escrever os comentários é a mesma para refatorar seu código. Você deveria escrever código que é legível pelos humanos. Há algum tempo, as linguagens tinham uma limitação no tamanho dos identificadores, assim os comentários eram a única alternativa para trazer algum significado para os outros seres humanos. A diferença está num princípio da refatoração, onde você deveria usar seu próprio código para embutir significado, escolhendo os nomes corretos para classes, métodos, variáveis e outros identificadores. Além disso, você deveria evitar usar os comentários para o mesmo propósito porque eles não são executados. Assim, rapidamente os comentários tornam-se obsoletos. Na pressa do cotidiano de trabalho, é fácil mudar o código e esquecer dos comentários, documentação, diagramas e outros artefatos secundários.

O que está errado com a Hungarian notation?

Talvez quem cunhou o termo Hungarian notation não tinha em mente apenas o idioma nativo de Charles Simonyi como inspiração. Eu não ficaria surpreso se nomes como a_crszkvc30LastNameCol e lpszFile soassem com húngaro para eles. Atualmente, os compiladores tomam conta do type safety e vão rastrear o tipo da informação. Nos IDEs modernos, toda a informação necessária a respeito do tipo pode ser encontrada no balão de sugestões (tip) ponteiro do seu mouse. Em linguagens como C# e VB.Net, a Hungarian notation não tem mais utilidade.

Nota do tradutor: Hungarian notation é uma convenção de nomes em linguagens de programação, onde o nome da variável indica seu tipo ou intenção de uso. (fonte: http://en.wikipedia.org/wiki/Hungarian_notation)

Novamente, mudar alguns antigos hábitos pode ser doloroso. Hungarian notation é frequentemente vista como uma prática útil na programação, que não pode ser implementada sem algum esforço. Não se admire se nem todo mundo ficar feliz com a notícia de que seu esquema de nomeação tradicional já ficou obsoleto.

Usar nomes fáceis de ler que lembram a linguagem humana natural vai melhorar muito a clareza de seu código. Largue aqueles prefixos engraçados e use palavras que outros humanos também possam entender facilmente.

Conclusão

Ao passo que provavelmente seria um exagero dizer que a refatoração está revolucionando a programação, ela está mudando alguns velhos hábitos cultivados. Ela tem provocado alguma resistência e uma boa quantidade de confusão em quem ainda não iniciou.

Eu espero que você ache esse artigo útil para iniciar o aprendizado da refatoração. Você não deveria recuar com alguns problemas que poderiam desmotivá-lo na primeira leitura. Se você está promovendo a refatoração, ou tentando educar outras pessoas sobre esse assunto, então você deveria estar preparado para questionamentos. Nesse caso, eu espero ter fornecido alguns argumentos que você poderia usar para justificar a verdadeira racionalidade por trás da refatoração e a necessidade de sua adoção.

Esse artigo foi extraído do livro "Professional Refactoring in Visual Basic" escrito por Danijel Arsenovski e publicado pela editora Wrox.

Sobre o Autor

Danijel Arsenovski é um dos autores do livro "Professional Refactoring in Visual Basic" publicado pela editora Wrox. Atualmente ele trabalha como Arquiteto de Produtos e Soluções na Excelsys S.A, projetando soluções de internet banking para vários clientes na região. Ele começou experimentando a refatoração enquanto mantinha um sistema bancário enorme, e não perdeu o interesse pela refatoração desde então. Ele foi pioneiro na adoção da refatoração como um guia para o upgrade de VB 6 para VB .NET. Arsenovski contribui para várias publicações, tem um certificado de Microsoft Certified Solution Developer (MCSD), e foi nomeado Visual Basic MVP em 2005. Você pode contactá-lo pelo e-mail danijel.arsenovski@empoweragile.com, ou dar uma olhada no blog dele em http://blog.vbrefactoring.com.

Olá visitante

Você precisa cadastrar-se no InfoQ Brasil ou para enviar comentários. Há muitas vantagens em se cadastrar.

Obtenha o máximo da experiência do InfoQ Brasil.

Dê sua opinião

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber mensagens dessa discussão
Comentários da comunidade

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber mensagens dessa discussão

HTML é permitido: a,b,br,blockquote,i,li,pre,u,ul,p

Receber mensagens dessa discussão

Dê sua opinião

Conteúdo educacional

Feedback geral
Bugs
Publicidade
Editorial
InfoQ Brasil e todo o seu conteúdo: todos os direitos reservados. © 2006-2014 C4Media Inc.
Política de privacidade
BT