4. O que é?
• “É o processo de realizar mudanças
em código existente e funcional sem
alterar seu comportamento”
!
• Alterar COMO o código
• NÃO alterar O QUE ele faz
!
• Aprimorar a estrutura interna
6. Refatoração
e TDD
• Após implementar o código mais simples
para fazer o teste passar
• refatoramos o código para remover as
duplicações que adicionamos para ver o
teste passar
• Como temos um conjunto seguro de
testes,
• então podemos refatorar com confiança
8. Motivação
• facilitar a adição de código novo
• melhorar o projeto existente
• obter um melhor entendimento de código
• tornar a programação menos irritante
10. Contextos
• quando existe duplicação de código
• quando a intenção é obscura
• percebemos que o código e/ou sua
intenção não são claros
• ex: lógica condicional complicada
• quando detectamos problemas de código
(“bad smells”)
• ou indícios de problemas
11. Duplicação
• Falência de um bom código
• Existem várias formas
• simples e óbvios
• índícios
• disfarçados
16. def save
if (arquivo.nil?)
return false
end
diretorio = Diretorio.new(arquivo)
diretorio.add(arquivo)
diretorio.close()
return true
end
def saveAs
arquivo = view.file
if (arquivo.nil?)
return false
end
diretorio = Diretorio.new(arquivo)
diretorio.add(arquivo)
diretorio.close()
return true
end
17. def save
if (arquivo.nil?) {
return false
}
diretorio = Diretorio.new(arquivo)
diretorio.add(arquivo)
diretorio.close()
return true
end
def saveAs
arquivo = view.file
save
end
22. O que torna um código
claro?
• Escolher bons nomes
• dicionário na mão para ajudar a
comunicar nossa intenção
• TDD
• Como escrevemos 1º o teste, somos
forçados a pensar na interface do
código antes da sua implementação
• oportunidade de pensar a partir do
ponto de vista do usuário da classe
29. Classes muito grandes
• Desproporcional às outras
• Por quê?
• tenta fazer muita coisa?
• possui muito código condicional?
• possui muito comportamento
condicional?
• Como identificar?
31. Switches
class Empregado
// 0 - engenheiro, 1 - vendedor, 2 - gerente
attr_accessor :tipo_empregado
!
def nome_do_departamento
case @tipo_empregado
when 0
return Engenheiro
when 1
return Vendedor
when 2
return Gerente
else
return Desconhecido
end
end
end
36. Refatorações
•
•
•
•
•
Extrair classe
Extrair interface
Extrair método
Substituir código
digitado por subclasses
ou objeto de valor
Substituir condicional
por polimorfismo
•
Utilizar métodos
gabaritos
•
Utilizar variavel
explicativa
•
Substituir construtores
por métodos fábrica
•
Substituir herança por
delegação
•
Substituir números
mágicos por constantes
37. Extrair Classe
• Contexto
• classes muito grandes
• comportamento disperso
• Solução
• fracionar as classes em pedaços menores
mais coesos
• Extração de comportamentos para uma
nova classe
38. class MovieListWriter
attr_accessor :destination
!
def initialize(aWriter = nil)
destination = aWriter;
end
!
def write_movie_list(a_list)
a_list.movies.each do |movie|
write_movie(movie)
end
end
!
def write_movie(a_movie)
destination.write(a_movie.name)
destination.write('|')
destination.write(a_movie.category.to_s)
destination.write('|')
begin
destination.write(a_movie.rating.to_s)
rescue UnratedException = ex
destination.write(-1)
end
destination.write('n')
end
end
39. class Movie
// ...
def write_to(destination)
destination.write(name)
destination.write('|')
destination.write(category.to_s)
destination.write('|')
begin
destination.write(rating.to_s)
rescue UnratedException = ex
destination.write(-1)
end
destination.write('n');
end
// ...
end
40. class MovieList
write_to(destination)
movies.each do |movie|
movie.write_to(destination)
end
end
end
41. Extrair Interface
• Contexto
• Se quer abstrair a forma de uma
implementação concreta
• Comportamentos importantes
substituíveis ou reversíveis
• Solução
• criar interfaces para poder substituir o
concreto tardiamente
42. public class MovieList {
private CollectionMovie movies =
new ArrayListMovie();
!
}
public int size() {
return movies.size();
}
public void add(Movie movieToAdd) {
movies.add(movieToAdd);
}
46. Extrair Método
• Contexto
• métodos muito longos
• lógicas de complexo entendimento
• Solução
• fracionar o método em métodos
menores mais coesos
• Extração de comportamentos para novos
métodos
47. public void init() {
}
getContentPane().setLayout(new FlowLayout());
movieList = new JList(myEditor.getMovies());
JScrollPane scroller = new JScrollPane(movieList);
getContentPane().add(scroller);
movieField = new JTextField(16);
getContentPane().add(movieField);
addButton = new JButton(Add);
....
48. public void init() {
// set the layout
getContentPane().setLayout(new FlowLayout());
!
// create the list
movieList = new JList(myEditor.getMovies());
JScrollPane scroller = new JScrollPane(movieList);
getContentPane().add(scroller);
!
// create the field
movieField = new JTextField(16);
getContentPane().add(movieField);
!
// create theadd button
addButton = new JButton(Add);
....
}
50. Extrair Método 2
• Se um trecho de código duplicado
diferentes do programa
Classe1
51. Extrair Método 2
•
Se as duplicatas de código devem permanecer
sempre iguais, ou seja, uma vez que se realize uma
alteração em uma delas, as demais devem refletir
a alteração
Classe1
52. public void doGet(HttpservletRequest request,
HttpServletResponse response)
throws ServletException, IOException{
String p = request.getParameter(“personagem”);
request.setAttribute(“personagem”, p);
//Mais código
}
!
public void doPost(HttpservletRequest request,
HttpServletResponse response)
throws ServletException, IOException{
String p = request.getParameter(“personagem”);
request.setAttribute(“personagem”, p);
//Mais código
}
53. •
Extraindo o método
Concentre o código que se repete em um único
lugar, por exemplo, em um método e leve as
dependências para lá
public void doGet(HtttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException{
String p = request.getParameter(“personagem”);
request.setAttribute(“personagem”, p);
//Mais código
}
public void novoMetodo(HtttpServletRequest request,
HttpServletResponse response)throws ServletException,
IOException{
String p = request.getParameter(“personagem”);
request.setAttribute(“personagem”, p);
//Mais código
}
55. Refatorações
•
•
•
•
•
Extrair classe
Extrair interface
Extrair método
Substituir código
digitado por subclasses
ou objetos de valor
Substituir condicional
por polimorfismo
•
Utilizar métodos
gabaritos
•
Utilizar variavel
explicativa
•
Substituir construtores
por métodos fábrica
•
Substituir herança por
delegação
•
Substituir números
mágicos por constantes
56. Substituir código
digitado por subclasses
• Contexto
• classes indicam subtipos através de
código digitado
• Solução
• Criar uma subclasse para cada alternativa
• Vantagem
• Evitam-se complexos condicionais
57. class Empregado
//0 - engenheiro, 1 - vendedor, 2 - gerente
attr_accessor :tipo_do_empregado
//..
end
58. class Empregado
// ...
end
!
class Engenheiro Empregado
// ...
end
!
class Vendedor Empregado
// ...
end
!
class Gerente Empregado
// ...
end
59.
60. Substituir condicional
por polimorfismo
• Contexto
• classes indicam subtipos através de
código digitado
• Solução
• Criar uma subclasse para cada alternativa
• Vantagem
• Evitam-se complexos condicionais
61. public class Empregado
// 0 - engenheiro, 1 - vendedor, 2 - gerente
attr_accessor :tipo_do_empregado
!
def nome_do_departamento
case @tipoDoEmpregado
when 0
return Engenharia
when 1
return Vendas
when 2
return Gerência
else
return Desconhecido
end
end
end
62. class Empregado
def nome_do_departamento
end
end
!
class Engenheiro Empregado
def nome_do_departamento
Engenharia
end
end
!
class Vendedor Empregado
def nome_do_departamento
Vendas
end
end
!
class Gerente extends Empregado
def nome_do_departamento
Gerência
end
end
63. Utilizar métodos
gabaritos
•
•
Contexto
•
métodos em subclasses executam passos
similares na mesma ordem
•
os passos são diferentes
Solução
•
extraia os passos para métodos com mesma
assinatura
•
•
crie um método gabarito final na superclasse
especialize os métodos nas subclasses
64. Contexto
public class Cafe {
public void prepararReceita(){
ferverAgua();
misturarCafeComAgua();
servirNaXicara();
adicionarAcucarELeite();
}
!
!
!
!
!
public class Cha {
!
public void prepararReceita(){
ferverAgua();
misturarChaComAgua();
servirNaXicara();
adicionarLimao();
}
69. •
Substituir construtor
por métodos fábrica
Contexto
•
existência de diversos construtores para criar
versões diferentes dos objetos
•
•
•
pode haver confusão por falta de clareza de
intenção do construtor
Solução
•
criar métodos fábrica estáticos
Vantagem
• código de melhor entendimento
70.
71. Como fazer
•
Execute um Extrair Método para isolar a lógica do
comportamento
•
•
o método deve ser de classe
repasse as dependências
•
•
Se o método fábrica não estiver no objeto desejado, utilize o
Mover Método
•
•
Teste
Teste
Remova o construtor original se não há chamadas a ele
82. Substituir herança por
delegação
•
•
Contexto
•
uma subclasse utiliza apenas uma parte da
interface de sua superclasse e não reutiliza os
dados
Solução
•
•
crie um campo do tipo da superclasse
•
remova a herança
refatore os métodos que utilizam o
comportamento da superclasse
83.
84.
85. Substituir números mágicos
por constantes ou enums
•
•
•
Contexto
•
valores literais no código que possuem um
significado
Solução
•
crie uma constante e nomeie-a com o seu
significado
•
substitua os valores literais pelas constantes
Vantagem
• código de melhor entendimento
88. Resumo
• Um pouco de refatoração
• o que é
• técnicas específicas
• alguns indicadores
• Existe problema?
• Deve-se refatorar em pequenos
incrementos
89. Bibliografia
• ASTELS, David. Test-Driven Development: A
Pratical Guide. Prentice Hall, 2003.
• FOWLER, Martin; BECK, Kent; BRANT,
John; Opdyke, William; ROBERTS, Don.
Refactoring: Improving The Design of Existing
Code.
• KERIEVSKY, Joshua. Refatoração Para
Padrões. Porto Alegre: Bookman, 2008.
90.
91. Bibliografia
• ASTELS, David. Test-Driven Development: A
Pratical Guide. Prentice Hall, 2003.
• FOWLER, Martin; BECK, Kent; BRANT,
John; Opdyke, William; ROBERTS, Don.
Refactoring: Improving The Design of Existing
Code.
• KERIEVSKY, Joshua. Refatoração Para
Padrões. Porto Alegre: Bookman, 2008.