Refatoração de Código: Compor Method

Receba em primeira mão, e com prioridade, os conteúdos Android exclusivos do Blog. Você receberá um email de confirmação. Somente depois de confirma-lo é que poderei lhe enviar os conteúdos exclusivos.

Email inválido.
Blog /Android /Refatoração de Código: Compor Method

Refatoração de Código: Compor Method

Vinícius Thiengo
(1286)
Go-ahead
"É a repetição das afirmações que leva à crença. Quando essa crença vira uma convicção profunda, tudo começa a acontecer."
Muhammad Ali
Kotlin Android
Capa do livro Desenvolvedor Kotlin Android - Bibliotecas para o dia a dia
TítuloDesenvolvedor Kotlin Android - Bibliotecas para o dia a dia
CategoriasAndroid, Kotlin
AutorVinícius Thiengo
Edição
Capítulos19
Páginas1035
Acessar Livro
Treinamento Oficial
Android: Prototipagem Profissional de Aplicativos
CursoAndroid: Prototipagem Profissional de Aplicativos
CategoriaAndroid
InstrutorVinícius Thiengo
NívelTodos os níveis
Vídeo aulas186
PlataformaUdemy
Acessar Curso
Receitas Android
Capa do livro Receitas Para Desenvolvedores Android
TítuloReceitas Para Desenvolvedores Android
CategoriaDesenvolvimento Android
AutorVinícius Thiengo
Edição
Ano2017
Capítulos20
Páginas936
Acessar Livro
Código Limpo
Capa do livro Refatorando Para Programas Limpos
TítuloRefatorando Para Programas Limpos
CategoriaEngenharia de Software
AutorVinícius Thiengo
Edição
Ano2017
Capítulos46
Páginas599
Acessar Livro
Quer aprender a programar para Android? Acesse abaixo o curso gratuito no Blog.
Conteúdo Exclusivo
Receba em primeira mão, e com prioridade, os conteúdos Android exclusivos do Blog.
Email inválido

Opa, blz?

Nesse artigo continuamos com a série sobre Refatoração de Código, com o propósito de se tornar um coder de alta performance. Dessa vez vamos abordar o método de refatoração Compor Method que está entre os mais simples e úteis

Diferente dos outros métodos de refatoração, o Compor Method tem dicas de refatoração e não passos específicos. Porém, antes de prosseguir é importante que você conheça o padrão Cláusula de Guarda.

Caso ainda não conheça o padrão informado acima, aqui no Blog temos um artigo somente sobre ele. Alias é um artigo bem pequeno, pois o Cláusula de Guarda consegue ser ainda mais simples que o Singleton:

Ressalto que apesar da categoria do artigo ser "Android", ele e todos os outros dessa série de artigos de engenharia de spftware podem ser utilizados em qualquer projeto que está utilizando o paradigma orientado a objetos.

Além do padrão Cláusula de Guarda ainda há outros três métodos de refatoração como pré-requisito do método proposto aqui. Mas esses explico logo abaixo, tendo em mente que são muito simples e não necessitam de artigos somente para eles.

Tópicos presentes no artigo:

Método de refatoração Internalizar Método

Esse método de refatoração é aplicado quando temos um método que, a principio, somente infla nossa classe, pois está sendo utilizado apenas uma vez ou porque é resultado de uma refatoração mal feita. Logo, o que esse método de refatoração prega é que nós developers devemos colocá-lo novamente no método que o originou ou então apenas colocá-lo dentro do método que o utiliza, nesse caso não necessariamente a origem dele.

Com isso extrairemos o código desse método não necessário e colocaremos esse código no local da chamada a ele no método cliente, que deve recebe-lo.

Método de refatoração Extrair Método

Sabe aqueles métodos com "n" linhas e condicionais e algumas vezes chamadas a outros métodos (incluindo também os construtores de classe)? São exatamente nesses métodos que deveríamos aplicar o método de refatoração Extrair Método, para podermos colocar mais intenção em nosso método complexo, dessa forma teríamos vários métodos extraídos, mas com nomes que diriam o que exatamente faz o código dele, intenção.

Método de refatoração Extrair Classe

Com esse método é possível criar uma nova classe partindo de outra classe que realiza mais de uma tarefa principal, com isso criando uma melhor divisão de código no projeto. Lembrando que um dos princípios de programação orientada a objetos é que cada classe deve ter somente uma única tarefa principal.

Esse método de refatoração é comumente aplicado em classes grandes, onde somente o tamanho delas já é um indício forte de que há mais de uma tarefa principal como responsabilidade dessas classes.

Motivação (Compor Method)

Colocando aqui um dos princípios de Kent Beck em Padrões de Implementação (2008) temos que: "devemos primeiro programar sem padrões e técnicas de performance em código, apenas devemos resolver o problema de lógica deferido a nós em um belo e longo método."

Ok, e depois disso, depois do problema lógico resolvido? Ai sim aplicamos alguns métodos de refatoração (ou padrões de projeto, diretamente) para colocar intenção no código, remover código repetido entre outras melhorias.

Ou seja, a motivação aqui é um código que foi finalizado, as saídas são consistentes com as entradas, porém esse ainda não passou por nenhum processo de melhoria.

Código de exemplo

O exemplo a seguir é o código de um método de uma classe de manipulação de listas. Ele é pequeno, mas pouco indica como faz sua tarefa, apesar do nome do método ser bem descritivo. Segue código do método add() de List:

public class List {
Object[] elementos;
int tamanho;
boolean somenteLeitura;

...
public void add( Object elemento ){

if ( somenteLeitura ){
int novoTamanho = tamanho + 1;

if ( novoTamanho > elementos.length ){
Object[] novosElementos = new Object[ elementos.length + 10 ];

for( int i = 0; i < tamanho; i++ ){
novosElementos[i] = elementos[i];
}
elementos = novosElementos;
}

elementos[ tamanho++ ] = elemento;
}
}
...
}

 

Em Mecânica vamos colocar mais intenção ao código melhorando principalmente a leitura dele para posteriores refatorações.

Mecânica

Como já informado no início do artigo, dessa vez temos uma série de dicas e não passos exatos. Seguem:

  • Pense pequeno: métodos compostos poucas vezes têm mais de dez linhas e em geral ficam em torno de cinco linhas de código;
  • Remova duplicação e código morto: remova código que não mais é utilizado, incluindo código dentro de comentário. Remova também código repetido, veja se o passo repetido não pode virar um método;
  • Comunique intenção: nomeie as entidades (métodos, parâmetros e variáveis) de forma que comuniquem a responsabilidade do código, evitando a necessidade de comentários;
  • Simplifique: quase um passo de meditação (sério), pois mesmo já tendo refatorado (ou não) veja como pode melhorar o código ainda mais e então melhore caso um novo caminho venha em mente;
  • Utilize o mesmo nível de detalhamento: se junto as chamadas de métodos em seu método composto também há lógica condicional complexa, então é uma boa prática colocar essa lógica condicional complexa dentro de um novo método para que o método composto tenha uma estrutura mais comunicativa quanto a tarefa dele.

Seguindo com a refatoração Compor Método, nosso primeiro passo é utilizar o padrão Cláusula de Guarda para colocar uma saída rápida em nosso código e remover o aninhamento do script principal. Segue novo código do método add():

...
public void add( Object elemento ){

/* Claúsula de Guarda */
if ( !somenteLeitura ) {
return;
}

int novoTamanho = tamanho + 1;
if ( novoTamanho > elementos.length ){
Object[] novosElementos = new Object[ elementos.length + 10 ];

for( int i = 0; i < tamanho; i++ ){
novosElementos[i] = elementos[i];
}
elementos = novosElementos;
}
elementos[ tamanho++ ] = elemento;
}
...

 

Nosso próximo passo é remover o valor (ou número) mágico 10 e colocá-lo em uma constante.

Número mágico?

São valores constantes no código (de qualquer tipo primitivo) que não estão dentro de tipos constantes ou variáveis. Esse valores “soltos” são chamados de valores mágicos e podem ser um tremendo problema para manutenção se você tiver de utilizá-los mais de uma vez.

Segue código refatorado:

public class List {
private final static int VALOR_INCREMENTACAO = 10;

...
public void add( Object elemento ){

/* Claúsula de Guarda */
if ( !somenteLeitura ) {
return;
}

int novoTamanho = tamanho + 1;
if ( novoTamanho > elementos.length ){
Object[] novosElementos = new Object[ elementos.length + VALOR_INCREMENTACAO ];

for( int i = 0; i < tamanho; i++ ){
novosElementos[i] = elementos[i];
}
elementos = novosElementos;
}
elementos[ tamanho++ ] = elemento;
}
...
}

 

O passo seguinte é aplicar o método de refatoração Extrair Método na condicional que verifica se o vetor elementos suporta ou não mais um elemento. Estamos falando desse condicional: if( novoTamanho > elementos.length ). Segue código:

public class List {
...
public void add( Object elemento ){
...

if ( capacidadeCompleta() ){
Object[] novosElementos = new Object[ elementos.length + VALOR_INCREMENTACAO ];

for( int i = 0; i < tamanho; i++ ){
novosElementos[i] = elementos[i];
}
elementos = novosElementos;
}
elementos[ tamanho++ ] = elemento;
}

private boolean capacidadeCompleta(){
return( (tamanho + 1) > elementos.length );
}
...
}

 

Novamente, em nosso próximo passo, aplicaremos Extrair Método, dessa vez no código que aumenta o tamanho do vetor. Segue código:

public class List {
private final static int VALOR_INCREMENTACAO = 10;
...
public void add( Object elemento ){
...

if ( capacidadeCompleta() ){
crescerVetor();
}
elementos[ tamanho++ ] = elemento;
}

private void crescerVetor(){
Object[] novosElementos = new Object[ elementos.length + VALOR_INCREMENTACAO ];
for( int i = 0; i < tamanho; i++ ){
novosElementos[i] = elementos[i];
}
elementos = novosElementos;
}
...
}

 

Para finalizar a refatoração vamos realocar a linha de código final, a que adiciona o elemento ao vetor elementos. Essa linha vai para um método exclusivo dela, isso permitirá que nosso método composto tenha todo o corpo no mesmo nível de detalhe, com somente chamadas a métodos. Segue código final refatorado:

public class List {
private final static int VALOR_INCREMENTACAO = 10;

Object[] elementos;
int tamanho;
boolean somenteLeitura;

public void add( Object elemento ){

if ( !somenteLeitura ) {
return;
}
if ( capacidadeCompleta() ){
crescerVetor();
}
addElemento( elemento );
}

private boolean capacidadeCompleta(){
return( tamanho + 1 > elementos.length );
}

private void crescerVetor(){
Object[] novosElementos = new Object[ elementos.length + VALOR_INCREMENTACAO ];

for( int i = 0; i < tamanho; i++ ){
novosElementos[i] = elementos[i];
}
elementos = novosElementos;
}

private boolean addElemento( Object elemento ){
elementos[ tamanho++ ] = elemento;
}
...
}

 

Com isso o método add() passa mais intenção no processamento de seu algoritmo e temos alguns novos métodos que podem ainda ser aproveitados por outros métodos internos a List.

Conclusão

Nesse exemplo não tivemos nenhum problema, mas em códigos maiores pode ser que tenhamos um resultado final com vários outros pequenos métodos, deixando a leitura da classe, por parte de outros developers, complicada. Logo nesse caso é preciso verificar se não podemos aplicar o método de refatoração Extrair Classe, onde uma nova classe seria criada com parte dos métodos da classe atual.

Outra problemática que pode ocorrer é um novo método, auxiliar ao método composto, com um corpo de processamento grande e não realizando somente uma tarefa, deixando o código dele confuso.

Nesse caso aplica-se o método de refatoração Internalizar Método para voltar com o corpo desse método para o método original e então se desfazendo dele. Dessa forma é refatorar novamente (aplicando Extrair Método, por exemplo) buscando um novo caminho. A criação de mais de um método é bem provável que seja esse novo caminho.

Algo que pode vir a sua mente é: Esses métodos pequenos criam mais chamadas em meu código acabando com o desempenho.

Nesse caso é prudente utilizar um medidor de desempenhos junto a linguagem que você escolheu para saber onde realmente é o gargalo, pois modificar o código atacando o trecho errado vai trazer somente perda de tempo.

Outros artigos da série

Abaixo listo todos os artigos liberados da série refatoração de código, continue os estudos:

Internalizar Singleton

Mover Embelezamento Para Decorator

Substituir Condicionais que Alteram Estado por State

Introduzir Objeto Nulo

Unificar Interfaces Com Adapter

Extrair Adapter

Mover Conhecimento de Criação Para Factory

Substituir Notificações Hard-Coded Por Observer

Substituir Código de Tipo Por Classe

Extrair Parâmetro

Unificar Interfaces

Limitar Instanciação Com Singleton

Mover Acumulação Para Parâmetro Coletor

Formar Template Method

Substituir Lógica Condicional Por Strategy

Introduzir Criação Polimórfica com Factory Method

Encapsular Classes Com Factory

Encadear Construtores

Substituir Construtores Por Métodos de Criação

Fontes

Refatoração Para Padrões.

Padrões de Implementação.

Vlw.

Receba em primeira mão, e com prioridade, os conteúdos Android exclusivos do Blog.
Email inválido

Relacionado

Código Limpo - Habilidades Práticas do Agile SoftwareCódigo Limpo - Habilidades Práticas do Agile SoftwareLivros
O Codificador Limpo - Um código de conduto para programadores profissionaisO Codificador Limpo - Um código de conduto para programadores profissionaisLivros
Padrões de Implementação - Um Catálogo de Padrões Indispensável Para o Dia a Dia do ProgramadorPadrões de Implementação - Um Catálogo de Padrões Indispensável Para o Dia a Dia do ProgramadorLivros
Refatoração Para PadrõesRefatoração Para PadrõesLivros

Compartilhar

Comentários Facebook

Comentários Blog

Para código / script, coloque entre [code] e [/code] para receber marcação especifica.
Forneça seu nome válido.
Forneça seu email válido.
Forneça o comentário.
Enviando, aguarde...