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.
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
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:
- Definir como serão reorganizadas as responsabilidades da classe;
- 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;
- 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;
- 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;
- 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;
- 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
É 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
-
DevCast
-
DevCast
-
Artigo
-
Artigo
-
Artigo