1
|
|
2
|
- Vinicius Manhaes Teles, Extreme Programming, Novatec Editora
- Agile Software Development
- Scrum and XP from the Trenches
- Martin Fowler, Analysis Patterns - Reusable Object Models,
Addison-Wesley,1997
- Martin Fowler, Refatoração - Aperfeiçoando o projeto de código existente,
Ed Bookman
- Martin Fowler. Refactoring: improving the design of existing code.
Addison-Wesley. 2000.
|
3
|
- Introduction
- Extract Method
- Inline Method
- Replace Temp with Query
- Replace Inheritance With Delegation
- Collapse Hierarchy
- Replace Conditional With Polymorphism
- Introduce Null Object
- Princípios Básicos
|
4
|
|
5
|
- Uma [pequena] modificação no sistema que não altera o seu comportamento
funcional,
- mas que melhora alguma qualidade não-funcional:
- simplicidade
- flexibilidade
- clareza
- desempenho
|
6
|
- Mudança do nome de variáveis
- Mudanças nas interfaces dos objetos
- Pequenas mudanças arquiteturais
- Encapsular código repetido em um novo método
- Generalização de métodos
- raizQuadrada(float x)Þ
raiz(float x, int n)
|
7
|
- 1. Melhorar código antigo e/ou
feito por outros programadores.
- 2. Desenvolvimento incremental à
la XP.
- Em geral, um passo de refatoramento é tão simples que parece que ele não
vai ajudar muito.
- Mas quando se juntam 50 passos, bem escolhidos, em seqüência, o código
melhora radicalmente.
|
8
|
- Cada passo é trivial.
- Demora alguns segundos ou alguns poucos minutos para ser realizado.
- É uma operação sistemática e óbvia (ovo de Colombo).
- O segredo está em ter um bom vocabulário de refatoramentos e saber
aplicá-los criteriosamente e sistematicamente.
|
9
|
- Mas não tinha um nome.
- Estava implícito, ad hoc.
- A novidade está em criar um vocabulário comum e em catalogá-los.
- Assim podemos utilizá-los mais sistematicamente.
- Podemos aprender novas técnicas, ensinar uns aos outros.
|
10
|
- Sempre há duas possibilidades:
- 1. Melhorar o código existente.
- 2. Jogar fora e começar do 0.
- É sua responsabilidade avaliar a situação e decidir quando é a hora de
optar por um ou por outro.
|
11
|
- Surgiu na comunidade de Smalltalk nos anos 80/90.
- Desenvolveu-se formalmente na Universidade de Illinois em
Urbana-Champaign.
- Grupo do Prof. Ralph Johnson.
- Tese de PhD de William Opdyke (1992).
- John Brant e Don Roberts:
- The Refactoring Browser Tool
- Kent Beck (XP) na indústria.
|
12
|
- Hoje em dia é um dos preceitos básicos de Programação eXtrema (XP).
- Mas não está limitado a XP, qualquer um pode (e deve) usar em qualquer
contexto.
- Não é limitado a Smalltalk.
- Pode ser usado em qualquer linguagem [orientada a objetos].
|
13
|
- [Fowler, 2000] contém 72 refatoramentos.
- Análogo aos padrões de desenho orientado a objetos [Gamma et al. 1995]
(GoF).
- Vale a pena gastar algumas horas com [Fowler, 2000].
- (GoF é obrigatório, não tem opção).
|
14
|
- Quando você tem que adicionar
uma funcionalidade a um programa e o código do programa não está
estruturado de uma forma que torne a implementação desta funcionalidade
conveniente, primeiro refatore de modo a facilitar a implementação da
funcionalidade e, só depois, implemente-a.
|
15
|
- Antes de começar o refatoramento, verifique se você tem um conjunto
sólido de testes para verificar a funcionalidade do código a ser
fatorado.
- Refatoramentos podem adicionar erros.
- Os testes vão ajudá-lo a detectar erros se eles forem criados.
|
16
|
- Os testes devem verificar a si mesmos.
- A saída deve ser
- “OK” ou
- lista precisa das coisas que deram errado.
- Quando os testes funcionam, sua saída deve ser apenas uma lista enxuta
de “Oks”.
- Ou um botão e uma luz verde e outra vermelha.
|
17
|
|
18
|
- Nome do refatoramento.
- Resumo da situação na qual ele é necessário e o que ele faz.
- Motivação para usá-lo (e quando não usá-lo).
- Mecânica, i.e., descrição passo a passo.
- Exemplos para ilustrar o uso.
|
19
|
|
20
|
- Nome: Extract Method
- Resumo: Você tem um fragmento de código que poderia ser agrupado. Mude o
fragmento para um novo método e escolha um nome que explique o que ele
faz.
- Motivação: é um dos refatoramentos mais comuns. Se um método é longo
demais ou difícil de entender e exige muitos comentários, extraia
trechos do método e crie novos métodos para eles. Isso vai melhorar as
chances de reutilização do código e vai fazer com que os métodos que o
chamam fiquem mais fáceis de entender. O código fica parecendo
comentário.
|
21
|
- Mecânica:
- Crie um novo método e escolha um nome que explicite a sua intenção (o
nome deve dizer o que ele faz, não como ele faz).
- Copie o código do método original para o novo.
- Procure por variáveis locais e parâmetros utilizados pelo código
extraído.
- Se variáveis locais forem usados apenas pelo código extraído, passe-as
para o novo método.
- Caso contrário, veja se o seu valor é apenas atualizado pelo código.
Neste caso substitua o código por uma atribuição.
- Se é tanto lido quando atualizado, passe-a como parâmetro.
- Compile e teste.
|
22
|
- void imprimeDivida () {
- Enumerate e = _pedidos.elementos ();
- double divida = 0.0;
- // imprime cabeçalho
- System.out.println (“***************************”);
- System.out.println (“*** Dívidas do Cliente ****”);
- System.out.println (“***************************”);
- // calcula dívidas
- while (e.temMaisElementos ()){
- Order cada = (Order) e.proximoElemento ();
- divida += cada.valor ();
- }
- // imprime detalhes
- System.out.println (“nome: ” + _nome);
- System.out.println (“divida total: ” + divida);
- }
|
23
|
- void imprimeDivida () {
- Enumerate e = _pedidos.elementos ();
- double divida = 0.0;
- imprimeCabecalho ();
- // calcula dívidas
- while (e.temMaisElementos ()){
- Order cada = (Order) e.proximoElemento ();
- divida += cada.valor ();
- }
- //imprime detalhes
- System.out.println(“nome: ” + _nome);
- System.out.println(“divida total: ” + divida);
- }
- void imprimeCabecalho () {
- System.out.println
(“***************************”);
- System.out.println (“*** Dívidas do Cliente ****”);
- System.out.println (“***************************”);
- }
|
24
|
- void imprimeDivida () {
- Enumerate e = _pedidos.elementos ();
- double divida = 0.0;
- imprimeCabecalho ();
- // calcula dívidas
- while (e.temMaisElementos ()){
- Order cada = (Order) e.proximoElemento ();
- divida += cada.valor ();
- }
- imprimeDetalhes (divida);
- }
- void imprimeDetalhes (divida)
- {
- System.out.println(“nome: ” + _nome);
- System.out.println(“divida total: ” + divida);
- }
|
25
|
- void imprimeDivida () {
- imprimeCabecalho ();
- double divida = calculaDivida ();
- imprimeDetalhes (divida);
- }
- double calculaDivida ()
- {
- Enumerate e = _pedidos.elementos ();
- double divida = 0.0;
- while (e.temMaisElementos ()){
- Order cada = (Order) e.proximoElemento ();
- divida += cada.valor ();
- }
- return divida;
- }
|
26
|
- void imprimeDivida () {
- imprimeCabecalho ();
- double divida = calculaDivida ();
- imprimeDetalhes (divida);
- }
- double calculaDivida ()
- {
- Enumerate e = _pedidos.elementos ();
- double resultado = 0.0;
- while (e.temMaisElementos ()){
- Order cada = (Order) e.proximoElemento ();
- resultado += cada.valor ();
- }
- return resultado;
- }
|
27
|
- void imprimeDivida (double dividaAntiga) {
- Enumerate e = _pedidos.elementos ();
- double divida = dividaAntiga * 1.2;
- imprimeCabecalho ();
- // calcula dívidas
- while (e.temMaisElementos ()){
- Order cada = (Order) e.proximoElemento ();
- divida += cada.valor ();
- }
- imprimeDetalhes (divida);
- }
- void imprimeDetalhes (divida)
- {
- System.out.println(“nome: ” + _nome);
- System.out.println(“divida total: ” + divida);
- }
|
28
|
- void imprimeDivida (double dividaAntiga) {
- imprimeCabecalho ();
- double divida = calculaDivida (dividaAntiga * 1.2);
- imprimeDetalhes (divida);
- }
- double calculaDivida (double valorInicial)
- {
- Enumerate e = _pedidos.elementos ();
- double resultado = valorInicial;
- while (e.temMaisElementos ()){
- Order cada = (Order) e.proximoElemento ();
- resultado += cada.valor ();
- }
- return resultado;
- }
|
29
|
- E se mais do que um valor deve ser retornado ?
- Escolha um subconjunto do código;
- Pode-se passar por referência (evitar);
- O quê fazer com variáveis temporárias?
- Usar Replace Temp with Query (120)
- Ou trocar método por método objeto (135)
|
30
|
|
31
|
- Nome: Inline Method
- Resumo: a implementação de um método é tão clara quanto o nome do
método. Substitua a chamada ao método pela sua implementação.
- Motivação: bom para eliminar indireção desnecessária. Se você tem um
grupo de métodos mau organizados, aplique Inline Method em todos eles seguido de uns bons Extract
Method s.
|
32
|
- Mecânica:
- Verifique se o método não é polimórfico ou se as suas subclasses o
especializam
- Ache todas as chamadas e substitua pela implementação
- Compile e teste
- Remova a definição do método
- Dica: se for difícil -> não faça.
- Exemplo:
- int bandeiradaDoTaxi (int hora) {
- return (depoisDas22Horas(hora)) ? 2 : 1);
- }
- int depoisDas22Horas(int hora) {
- return hora > 22;
- }
|
33
|
|
34
|
- Nome: Replace Temp with Query
- Resumo: Uma variável local está sendo usada para guardar o resultado de
uma expressão. Troque as referências a esta expressão por um método.
- Motivação: Variáveis temporárias encorajam métodos longos (devido ao
escopo). O código fica mais limpo e o método pode ser usado em outros
locais.
|
35
|
- Mecânica:
- Encontre variáveis locais que são atribuídas uma única vez
- Se temp é atribuída mais do que uma vez - Split Temporary Variable
(128)
- Declare temp como final
- Compile (para ter certeza)
- Extraia a expressão
- Método privado - efeitos colaterais
- Compile e teste
|
36
|
|
37
|
|
38
|
|
39
|
|
40
|
|
41
|
|
42
|
|
43
|
- Resumo: Quando uma subclasse só usa parte da funcionalidade da
superclasse ou não precisa herdar dados: na subclasse, crie um campo
para a superclasse, ajuste os métodos apropriados para delegar para a
ex-superclasse e remova a herança.
- Motivação: herança é uma técnica excelente, mas muitas vezes, não é
exatamente o que você quer. Às vezes, nós começamos herdando de uma
outra classe mas daí descobrimos que precisamos herdar muito pouco da
superclasse. Descobrimos que muitas das operações da superclasse não se
aplicam à subclasse. Neste caso, delegação é mais apropriado.
|
44
|
- Mecânica:
- Crie um campo na subclasse que se refere a uma instância da
superclasse, inicialize-o com this
- Mude cada método na subclasse para que use o campo delegado
- Compile e teste após mudar cada método
- Cuidado com as chamadas a super
- Remova a herança e crie um novo objeto da superclasse
- Para cada método da superclasse utilizado, adicione um método delegado
- Compile e teste
|
45
|
- Exemplo: pilha subclasse de vetor.
- Class MyStack extends Vector {
- public void push (Object element) {
- insertElementAt (element, 0);
- }
- public Object pop () {
- Object result = firstElement ();
- removeElementAt (0);
- return result;
- }
|
46
|
- Crio campo para superclasse.
- Class MyStack extends Vector {
- private Vector _vector = this;
- public void push (Object element) {
- _vector.insertElementAt (element, 0);
- }
- public Object pop () {
- Object result = _vector.firstElement ();
- _vector.removeElementAt (0);
- return result;
- }
|
47
|
- Removo herança.
- Class MyStack extends Vector {
- private Vector _vector = this; new Vector ();
- public void push (Object element) {
- _vector.insertElementAt (element, 0);
- }
- public Object pop () {
- Object result = _vector.firstElement ();
- _vector.removeElementAt (0);
- return result;
- }
|
48
|
- Crio os métodos de delegação que serão necessários.
- public int size () {
- return _vector.size ();
- }
- public int isEmpty () {
- return _vector.isEmpty ();
- }
- }// end of class MyStack
|
49
|
|
50
|
- Resumo: A superclasse e a subclasse não são muito diferentes. Combine-as
em apenas uma classe.
- Motivação: Depois de muito trabalhar com uma hierarquia de classes, ela
pode se tornar muito complexa. Depois de refatorá-la movendo métodos e
campos para cima e para baixo, você pode descobrir que uma subclasse não
acrescenta nada ao seu desenho. Remova-a.
|
51
|
- Mecânica:
- Escolha que classe será eliminada: a superclasse ou a subclasse
- Use Pull Up Field (320) and Pull Up Method (322) ou Push Down Method
(328) e Push Down Field (329) para mover todo o comportamento e dados
da classe a ser eliminada
- Compile e teste a cada movimento
- Ajuste as referências a classe que será eliminada
- isto afeta: declarações, tipos de parâmetros e construtores.
- Remove a classe vazia
- Compile e teste
|
52
|
|
53
|
- class Viajante {
- double getBebida () {
- switch (_type) {
- case ALEMAO:
- return cerveja;
- case BRASILEIRO:
- return pinga + limao;
- case AMERICANO:
- return coca_cola;
- }
- throw new RunTimeException (“Tipo desconhecido!”);
- }
- }
|
54
|
- class Alemao extends Viajante {
- double getBebida () {
- return cerveja;
- }
- }
- class Brasileiro extends Viajante {
- double getBebida () {
- return pinga + limao;
- }
- }
- class Americano extends Viajante {
- double getBebida () {
- return coca_cola;
- }
- }
|
55
|
|
56
|
- Result meuORBCorba (String parametros[])
- {
- Result r;
- if (pre_interceptor != NULL)
- pre_interceptor.chamada ();
- if (meuObjeto != NULL && meuObjeto.metodo != NULL)
- r = meuObjeto.metodo.invoke (parametros);
- if (pos_interceptor != NULL)
- r = pos_interceptor.chamada (r);
- return r;
- }
|
57
|
- Substitua o valor NULL por um objeto do tipo Nulo.
- Result meuORBCorba (String parametros[])
- {
- pre_interceptor.chamada ();
- Result r = meuObjeto.metodo.invoke (parametros);
- return pos_interceptor.chamada (r);
- }
|
58
|
|
59
|
- Quando o código cheira mau, refatore-o!
|
60
|
- Quando o código cheira mau, refatore-o!
|
61
|
- Refatoramento, muda o programa em passos pequenos. Se você comete um
erro, é fácil consertar.
- Qualquer um pode escrever código que o computador consegue entender.
Bons programadores escrevem código que pessoas conseguem entender.
- Três repetições? Está na hora de refatorar.
- Quando você sente que é preciso escrever um comentário para explicar o
código melhor, tente refatorar primeiro.
|
62
|
- Os testes tem que ser automáticos e ser capazes de se auto-verificarem.
- Uma bateria de testes é um exterminador de bugs que pode lhe economizar
muito tempo.
- Quando você recebe um aviso de bug, primeiro escreva um teste que
reflita esse bug.
- Pense nas situações limítrofes onde as coisas podem dar errado e
concentre os seus testes ali.
|
63
|
- Refactoring Browser Tool.
- Dá suporte automatizado para uma série de refatoramentos.
- Pode melhorar em muito a produtividade.
- Já existem há vários anos para Smalltalk.
- Há alguns (experimentais) para C++ e Java.
- Iniciativas acadêmicas (Ralph@UIUC).
|
64
|
- “It completely changes the way you think about programming”. “Now I use probably half [of the time]
refactoring and half entering new code, all at the same speed”. Kent
Beck.
- A ferramenta torna o refatoramento tão simples que nós mudamos a nossa
prática de programação.
- http://st-www.cs.uiuc.edu/~brant/RefactoringBrowser
|
65
|
|
66
|
- Refactoring is cool.
- Bibliografia:
- Martin Fowler. Refactoring: improving the design of existing code.
Addison-Wesley. 2000.
|