Refatorando no Agile:

Como Fazer Mudanças no Design de Forma Segura e Eficaz

Software Dev
Como gerente de desenvolvimento de software você acabou de herdar uma grande base de código e todos estão esperando que você apresente novas funcionalidades cruciais. De preferência para ontem. Você adoraria fazer isso. Mas nem você nem sua equipe entendem o código. A refatoração do código poderia ajudá-lo? Afinal de contas, a refatoração de código no Agile está bem popular. Você ouve dizer que é isso que mantém as equipes capazes de responder às mudanças rapidamente. E isso é exatamente o que você precisa. Mas nem você nem sua equipe têm experiência com isso. Você está procurando um bom começo, para entender os fundamentos e receber orientação sobre como praticá-lo. Bem, você está no lugar certo. Este artigo irá equipá-lo com os fundamentos certos, assim você logo estará bem encaminhado para refatorar a base de códigos existente e adicionar novas funcionalidades.

Breve Resumo
Com o tempo, o design do software tende a se degradar, e os sistemas se tornam cada vez mais difíceis de mudar.

A refatoração de código visa evitar que o software se degrade ou, quando já está degradado, melhorar seu design para que se torne mais fácil de entender e mudar.

A refatoração de código é importante para eliminar falhas de projeto, conseguir a manutenção e a extensibilidade de um sistema de software.

Crucialmente, a refatoração de código muda o design do código, mas nunca o comportamento do software. Os dois jamais devem se misturar.

Breve História: O Nascimento da Refatoração
A refatoração não foi um acidente feliz.

Os programadores têm limpado, reorganizado e reestruturado instintivamente seu código desde que os primeiros programas foram escritos.

Então, no final dos anos 80, dois estudantes de pós-graduação em informática da época (William Opdyke na Universidade de Illinois em Urbana-Champaign e William Griswold na Universidade de Washington), inventaram independentemente o que agora é chamado de refatoração de software.

Pesquisador

William Griswold

  • Jovem estudante de pós-graduação em Ciência da Computação
  • Relativamente inexperiente no trabalho fora da universidade
  • 1985-86: Iniciou o programa de doutorado na Universidade de Washington e começou a trabalhar com David Notkin

William Opdyke

  • Estudante de Ciência da Computação
  • Experiência em desenvolvimento de software no Bell Labs envolvendo centenas ou milhares de funcionários, dando suporte a produtos com tempo de vida útil de 10 a 20 anos ou mais.
  • 1988: Início do programa de doutorado na Universidade de Illinois em Urbana-Champaign
Foco da Pesquisa

Evolução de Software

Uma vez implantadas as aplicações, elas não podiam mais ser alteradas.

Mudança de Software

Incluindo engenharia de software baseada no conhecimento, transformação de programas e evolução de esquemas de banco de dados.

Influenciadores Iniciais

1987:

  • Tony Hoare e o artigo de seu colega: Leis da programação.
  • Princípio fundamental: Transformar algebricamente um design de um programa em qualquer outro design possível.

1988:

  • A proposta de Notkin: Reestruturar os programas para melhorar seu design.
  • Griswold ampliou a proposta de Notkin de que as reestruturações deveriam preservar o significado.

1986:

  • Artigo de Fred Brooks — No Silver Bullet
  • Compartilhou a ideia chave: “Desenvolva — não construa — software”
  • O curso de Ralph Johnson em programação orientada a objetos promove a reusabilidade e a ideia de melhorar o design do código. 
  • Outros influenciadores-chave: uma equipe de pesquisa da Tektronix que incluía Kent Beck, Ward Cunningham e Rebecca Wirfs-Brock.

1990:

  • Opdyke e Johnson são autores de “Refactoring: An Aid in Designing Application Frameworks and Evaluating Object-Oriented Systems”.
Principal Motivador
  • Como construir uma ferramenta para apoiar a reestruturação com preservação do significado?
  • Como programar operações de reestruturação (refatorações) que apoiem o design, a evolução e a reutilização de frameworks de aplicação orientadas a objetos.
Contribuições Chave

1991:

  • Griswold completou sua dissertação.
  • A ferramenta de linha de comando automatizou um modesto catálogo de transformações que preservam o significado.
  • Demonstrou que você pode realizar uma rearquitetura sofisticada de uma aplicação usando apenas transformações que preservam o significado.

1992:

  • Opdyke completou sua dissertação.
  • Que refatorações você deve aplicar em uma determinada situação? 
  • Como, se de fato, você pode refatorar com segurança em uma determinada situação?
  • Demonstrou como você poderia alcançar mudanças funcionais significativas e melhorias no design do sistema ao compor uma série de mudanças mais primitivas.
  • Opdyke apresentou Martin Fowler à sua pesquisa de refatoração.
Contribuições Únicas
  • Focado nos aspectos de preservação do significado da refatoração.
  • Focado nas oportunidades únicas de refatoração de programas orientados a objetos.

Como Funciona

O que é Refatoração?

A refatoração de código é mudar o código com duas restrições cruciais:

  1. As mudanças tornam o código mais fácil de entender e, portanto, mais barato de modificar.
  2. As mudanças nunca mudam a funcionalidade, o comportamento observável, do código.

Essa segunda restrição deve ser repetida: uma refatoração nunca deve mudar o comportamento de um programa. Isto significa que se o programa for chamado antes e depois de uma refatoração com o mesmo conjunto de entradas, o conjunto resultante de valores de saída será o mesmo.

Você também ouvirá sobre a refatoração usada como substantivo e verbo. E aqui está uma definição rápida.

Refatoração (substantivo): uma mudança feita na estrutura interna do software para facilitar a compreensão e baratear a modificação sem alterar seu comportamento observável.

Refatorar (verbo): reestruturar o software aplicando uma série de refatorações sem alterar seu comportamento observável.

Por Que Você Deve Refatorar?

Se o código funcionar, a refatoração não é um revestimento de ouro? Uma perda de tempo? Um exercício mental para manter seu faturamento por hora? Entreter-se enquanto tenta fazer de seu código o melhor de algum ponto de vista purista, ou há algum valor real em fazer isso?

Code Refactor

Acontece que a refatoração é como você melhora o design e a qualidade do seu código. E se você parar de trabalhar em seu código assim que ele parecer funcionar, é muito provável que ele não esteja bem adaptado a mudanças futuras. E, portanto, as mudanças futuras serão mais caras.

Quando Você Deve Refatorar?

Se seu sistema tem muitas dívidas técnicas, você deveria parar de trabalhar em novas funcionalidades e passar algumas semanas refatorando? Às vezes isto pode fazer sentido, mas existem certos problemas com esta estratégia.

Vamos ilustrar isto com uma analogia:

When To Refactor

Imagine que você é um chefe de cozinha em um restaurante chique. Você está no negócio há seis meses e já estabeleceu alguns clientes regulares. No entanto, as coisas têm estado bastante ocupadas e você deixou escapar a limpeza. O estado de sua cozinha e de suas panelas e frigideiras interfere na sua capacidade de entregar refeições de bom gosto antes que seus convidados fiquem impacientes e saiam.

Depois de algumas escapadas e de uma visita do inspetor sanitário, é hora de debugar a cozinha, por assim dizer. Mas você não pode simplesmente fechar seu restaurante por algumas semanas enquanto você limpa tudo, pode? Seus clientes habituais podem tolerar isso, mas não é garantido e você definitivamente perderá muitos negócios de visitantes casuais.

O mesmo se aplica ao desenvolvimento de software.

A interrupção das operações, a criação de valor com funcionalidades novas ou melhoradas, dificilmente irá bem com seu cliente, stakeholders e gerentes.

Os bons restaurantes não funcionam assim. Eles não deixam que as questões de limpeza sejam desmarcadas a ponto de precisarem ser fechados. Note que eu disse bons restaurantes. Eles fazem da limpeza e manutenção uma parte regular de suas operações contínuas.

E, mais uma vez, o mesmo se aplica ao desenvolvimento de software.

A refatoração regular do código é como limpar sua cozinha. É muito mais eficaz em mantê-lo capaz de responder a novos requisitos e entregar valor a seus usuários ou clientes.

Quando Não Refatorar?

Há momentos em que você não deve refatorar.

A refatoração nunca deve mudar o comportamento do código.

Isto significa que você precisa ser capaz de verificar o comportamento de seu código. Todo o seu código, não apenas os pedaços que você mudou.

Portanto, você não pode, e nem mesmo quer refatorar, quando:

When Not To Refactor
  • Você está no meio de uma mudança funcional. Ainda menos quando você está lutando para fazer com que essa mudança funcione. Frequentemente, isso resulta em uma toca de coelho. Ou duas ou três. O que você quer fazer é colocar o programa de volta em um bom estado já conhecido. Então, refatore-o para que sua mudança funcional seja mais fácil de fazer. E só então volte para a mudança funcional.
  • Você tem uma aplicação com uma dívida técnica maciça e poucos, se houver, testes automatizados para verificar seu comportamento. O que você quer fazer neste caso é aplicar uma técnica chamada Golden Master. Ela envolve ter um grande conjunto de entradas para rodar através da aplicação e comparar a saída antes e depois de uma mudança de código. Desta forma, você pode verificar as bases de código que de outra forma são “não testáveis” e você pode encontrar uma maneira de torná-las mais testáveis através da refatoração. Outra maneira de proceder é declarar falência técnica da dívida e criar uma aplicação Strangler Fig que “estrangula” e substitui a atual.
  • Você tem um prazo imediato a cumprir. Seu melhor caminho é adiar uma refatoração para depois desse prazo ter sido cumprido. No entanto, quando você assume conscientemente uma dívida técnica, você precisa pagá-la logo após o prazo. Isso porque o caminho mais rápido para a falência técnica é sempre colocar o prazo, o curto prazo, antes de pagar a dívida, o longo prazo.

O Básico de Code Smells

Kent Beck cunhou o termo “code smells” nos anos 90. Code smells são sintomas, ou sinais, no código fonte de um programa que indicam um problema potencialmente mais profundo.

Em seu livro seminal “Refactoring”, Martin Fowler dá uma definição semelhante: “Um code smells é um sinal superficial que normalmente corresponde a um problema mais profundo no sistema”.

Os code smells não são bugs.

O código está correto e o programa funciona como deveria.

Em vez disso, eles mostram fraquezas no projeto do código que podem retardar o desenvolvimento ou aumentar o risco de bugs ou falhas no futuro.

Um exemplo de code smell é “Código Duplicado”: o mesmo código copiado e colado em vários lugares. É apenas uma questão de tempo até que alguém se esqueça de trocar uma dessas cópias junto com seus semelhantes.

A refatoração a ser aplicada para acabar com esse code smell é o “Método de Extração”: mesclando as cópias em uma função ou em um método de classe.

Como os code smells são “problemas à espera de acontecer”, é bom ter como objetivo zero code smells.

O Processo de Refatoração

Para minimizar a probabilidade de que você acidentalmente introduza bugs como parte de sua refatoração, você quer seguir um processo rigoroso.

Refactoring Process
  1. Certifique-se de que você pode recuar — restaurar a uma versão que comprovadamente funciona corretamente. Certifique-se de ter commitado todas as suas mudanças e que todos os testes realizados em relação ao código commitado foram bem sucedidos. Desta forma, você pode voltar a este ponto se sua refatoração não correr como você imaginava.
  2. Identifique o que você quer refatorar e como — que refatorações usar.
  3. Se você tiver vários refatoramentos a executar para realizar uma reestruturação maior, você pode selecionar um subconjunto de testes automatizados para verificar o comportamento inalterado após cada refatoração individual.
  4. Iterativamente: aplique uma refatoração e verifique se o comportamento não sofreu alterações. Se os testes mostram que você mudou o comportamento, mude o código, nunca os testes.
  5. Se você utilizou um subconjunto de testes automatizados durante o processo de refatoração, execute todos os testes para verificar o comportamento inalterado para a aplicação por inteira.
    Aqui novamente, se algo quebrou, altere o código para que os testes sejam aprovados — não altere os testes.
    Se você perceber que não vai conseguir fazer os testes passarem novamente em um período de tempo razoável, volte ao código funcional que você tinha antes do processo de refatoração.
  6. Avalie o efeito dos refatoramentos nas características de qualidade do software (por exemplo, complexidade, compreensibilidade, manutenção) ou no processo (por exemplo, produtividade, custo, esforço).
    Se não forem satisfatórios e não puderem ser melhorados facilmente, volte ao código funcional que você tinha antes do processo de refatoração.

Por que a Refatoração é Considerada Perigosa?

Não é. Eu nunca ouvi dizer que é perigoso.

Refactoring Dangers
No entanto, há alguns erros que você poderia cometer:
  • Você não usa ferramentas de refatoração automatizada e não tem cobertura de teste suficiente. Você pode falhar em completar uma refatoração corretamente.
  • Talvez você não esteja usando a Técnica Golden Master. O código que não tem testes muitas vezes não é projetado para ser testado. Para que o código possa ser testado, é preciso refatorá-lo. Vê como isto parece uma tarefa impossível? E a solução: O teste Golden Master prepara o caminho para poder começar a refatoração com segurança.
  • Você pode não estar ciente do “acesso reflexivo” a algumas das coisas (supostamente) privadas que você mudou. Algum outro código pode estar contornando os controles de acesso.
  • Você vai além de uma simples refatoração e termina em território de re-design. Quando você confunde as duas atividades, é provável que você cometa erros em ambas.
  • Você ‘refatorou’ uma API pública publicada — exceto que você não completou a tarefa porque não tem acesso aos clientes solicitantes. Eles simplesmente quebram.

A refatoração não é mais perigosa do que qualquer outra prática de programação, na realidade. Você tem que estar ciente do que pode dar errado e tomar medidas para evitar isso.

Um exemplo rápido: Método de Extração 

Problema

Você tem um fragmento de código que pode ser agrupado.

————————————————–

void PrintOwing()

{

  this.PrintBanner();

  // Print details.

  Console.WriteLine(“nome: ” + this.name);

Console.WriteLine(“quantidade:”+ this.GetOutstanding());

}

————————————————–

Solução

Mova este código para um novo método (ou função) separado e substitua o código antigo por uma chamada para o método.

————————————————–

void PrintOwing()

{

this.PrintBanner();

this.PrintDetails();

}

void PrintDetails()

{

Console.WriteLine(“nome: ” + this.name);

Console.WriteLine(“quantidade: ” + this.GetOutstanding());

}

————————————————–

Por que Refatorar

  • Quanto mais linhas se encontram em um método, mais difícil é descobrir o que o método faz. Esta é a principal razão para esta refatoração.
  • Além de eliminar a extensão em seu código, os métodos de extração também são um passo em muitas outras abordagens de refatoração.

Benefícios

  • Código mais legível! Certifique-se de dar ao novo método um nome que descreva a finalidade do método: createOrder(), renderCustomerInfo(), etc.
  • O mesmo nível de abstração em ambos os métodos, o que ajuda na compreensão do código.
  • Menos duplicação de código. Muitas vezes o código que é encontrado em um método pode ser reutilizado em outros lugares em seu programa. Assim, você pode substituir as duplicatas por chamadas para seu novo método.
  • Isola partes independentes do código, o que significa que os erros são menos prováveis (como se a variável errada for modificada).

Leitura Adicional

  1. W.F. Opdyke and R.E. Johnson, “Refactoring: An Aid in Designing Application Frameworks and Evolving Object-Oriented Systems,” Proc. 1990 Symp. Object-Oriented Programming Emphasizing Practical Applications (SOOPPA 90), 1990, pp. 274–282.
  2. W.G. Griswold and D. Notkin, “Automated Assistance for Program Restructuring,” ACM Trans. Software Eng. Methodology, vol. 2, no. 3, 1993, pp. 228–269.
  3. W.G. Griswold and D. Notkin, “Architectural Tradeoffs for a Meaning-Preserving Program Restructuring Tool,” IEEE Trans. Software Eng., vol. 21, no. 4, 1995, pp. 275–287.
  4. W.F. Opdyke, “Refactoring Object-Oriented Frameworks,” PhD diss., Dept. Computer Science, Univ. of Illinois at Urbana-Champaign, 1992.
  5. M. Fowler et al., Refactoring: Improving the Design of Existing Code, Addison-Wesley Longman, 1999.
  6. K. Beck, Extreme Programming Explained: Embrace Change, Addison-Wesley Longman, 1999.

Comece a Refatorar

Lembra-se daquela base de código que você herdou? Aquela que você e sua equipe não entendem? Que você se perguntava como satisfazer as expectativas de todos em relação a novas funcionalidades?

Agora você sabe como lidar com essa base de código com confiança.

Se há poucos ou nenhum teste, seu primeiro passo é criar um Golden Master.

Quando você tiver esse Golden Master, ou se você tiver a sorte de que a base de código tenha uma boa cobertura de testes, você pode proceder com a refatoração para facilitar a adição de novas funcionalidades, e adicionar essas novas funcionalidades. Tudo sem fechar para os negócios!

Então, vá em frente e comece a refatorar e adicionar as funcionalidades pelas quais todos estão esperando.

A vida é boa quando suas equipes Agile estão sincronizadas!

Contate-Nos hoje para uma demonstração personalizada do SwiftEnterprise! Ou inscreva-se para atualizações abaixo.