Refatorações em Ruby: Utilizando a técnica Extract Class

Conheça a técnica de refatoração Extract Class e saiba como utilizá-la na linguagem Ruby para melhorar a qualidade do seu código.

Motivação

A busca por um código de qualidade deveria ser uma premissa comum a todo desenvolvedor, bem como presente no cronograma de qualquer projeto. Muitas vezes, no entanto, com prazos curtos e a busca por entregas cada vez mais rápidas, o código acaba perdendo qualidade e elevando o custo de manutenção.

Uma das opções que visam melhorar a qualidade de código é conhecida como Refactoring. Essa opção oferece um conjunto de técnicas que possibilitam melhorar o design do código sem alterar a lógica de negócio, isto é, o resultado desejado pelo cliente. Nesse artigo vamos focar na técnica Extract Class, catalogada no grupo de refatorações Moving Features Between Objects, cujo objetivo é auxiliar na decisão de onde colocar as responsabilidades de cada elemento do código, possibilitando, de forma controlada, trocas de responsabilidades entre classes/objetos.

Aqui, aprenderemos como utilizar essa técnica na linguagem Ruby, abordando como executar cada etapa para obter um código mais coeso e menos acoplado.

Saiba mais sobre técnicas de refatoração em Ruby

Exemplo de código a ser refatorado

O Extract Class normalmente é utilizado quando uma classe está com baixa coesão, isto é, possui responsabilidades que não deveria. Para corrigir esse problema de design, cria-se uma nova classe, e os atributos e métodos da classe inicial que não estejam relacionados à responsabilidade dessa classe são movidos para a nova. Na Listagem 1 temos um exemplo de uma classe que pode ser refatorada com essa técnica.

01 class Funcionario 02 attr_reader :nome 03 attr_accessor :codigo_area_telefone 04 attr_accessor :nro_telefone 05 06 def numero_telefone 07 '(' + @codigo_area_telefone + ') ' + @nro_telefone 08 end 09 end
Listagem 1. Exemplo de código a ser refatorado com Extract Class.

Note que a classe Funcionario está pouco coesa, reunindo em um só lugar diferentes conceitos e responsabilidades, como possuir o nome de um funcionário e saber formatar o número de telefone (linhas 06 a 08). Pode-se imaginar a complexidade que essa classe acumulará à medida que mais atributos e comportamentos relacionados a funcionários forem adicionados a ela. Assim, conclui-se que essa classe é uma forte candidata a passar pela refatoração do tipo Extract Class.

Aplicando a refatoração

De forma geral, para realizar essa refatoração é preciso executar os seguintes passos:

  1. Definir como serão reorganizadas as responsabilidades da classe;
  2. Criar uma nova classe para “abrigar” as responsabilidades que deixarão de fazer parte da classe em refatoração. A partir dessas mudanças a antiga classe poderá receber um novo nome, para que melhor represente o seu objetivo;
  3. Criar, na classe antiga, uma referência para a nova, de forma a manter o comportamento desejado, porém, agora, utilizando os recursos da classe recém-criada;
  4. Utilizar a refatoração Move Field para cada atributo que necessite ser movido. A cada movimento deve-se testar para verificar se as funcionalidades continuam se comportando como anteriormente;
  5. Utilizar a refatoração Move Method, para cada método que necessite ser movido. A cada Move Method também devem ser realizados testes para verificar se o código continua funcionando normalmente;
  6. Avaliar se múltiplos clientes poderão acessar a classe criada. Se forem permitidos múltiplos clientes, a nova classe deve ser acessada por um objeto de referência ou por um Value Object imutável (padrão de projeto muito utilizado).

Após esse processo, tomando como base o exemplo da Listagem 1, pode-se obter o resultado apresentado na Listagem 2.

01 class TelefoneNumero 02 #Também foram realizadas as refatorações Move Field e Move Method 03 #para trazer o método numero_telefone e os devidos atributos 04 attr_accessor : codigo_area_telefone, :nro_telefone 05 06 def numero_telefone 07 '(' + codigo_area_telefone + ') ' + nro_telefone 08 end 09 end 10 11 12 class Funcionario 13 attr_reader :nome 14 15 def initialize 16 @telefonenumero = TelefoneNumero.new 17 end 18 19 def numero_telefone 20 @telefonenumero.numero_telefone 21 end 22 23 def telefonenumero 24 @telefonenumero 25 end 26 end
Listagem 2. Exemplo de código refatorado com Extract Class.

É possível verificar que foi criada a classe TelefoneNumero (linhas 1 a 9), responsável pelos dados e comportamento relacionados ao número de telefone. Já em Funcionario, foi criado um link para conectar essa classe à classe TelefoneNumero (linhas 19 a 21), de forma a obter o número de telefone completo.

As boas práticas da Orientação a Objetos sugerem que uma classe deve respeitar o princípio da responsabilidade única. No entanto, é comum que com o passar do tempo uma classe passe a receber novas operações e dados, tornando-se mais complexa e assumindo responsabilidades que não deveriam fazer parte do seu escopo. Quando isso for observado, deve-se considerar a possibilidade de aplicar a refatoração.

Artigos relacionados