SlideShare uma empresa Scribd logo
1 de 130
Baixar para ler offline
Refactoring e Code Smells: 
Seu código está apodrecendo!
Emanuel Canuto 
Desenvolvimento há 4 
UECE 
Rock! 
Pensar 
Mantér a simplicidade 
Aprender 
@emanuel_canuto
Desenvolvimento de software ágil é f*da!
caso contrário seria músico
CAFÉ!!!
Tava precisando! 
@handersonbf 
https://www.facebook.com/photo.php?fbid=10203189806695222&set=p.10203189806695222&type=1&permPage=1
Mudar é evoluir!
FFFFiiiigggghhhhtttt !!!!!!!!
Quem trabalha ou já trabalhou 
em algum projeto 
Bugado???
Quem já bugou um 
projeto ???
Pense! Quais foram 
as experiências ???
Rigidez 
Parece simples, mas difícil de mudar 
Mudanças em cascata 
Dependências entre módulos 
Medo de correção de bugs
Fragilidade 
Code and Fix 
Manutenção Adventure 
Desenvolvimento fora de controle 
Credibilidade começa a cair 
Terminei a feature!!! 
Ei mah, tua feature quebrou!
Imobilidade 
Não é possível reutilizar software 
Muitas Dependências 
Responsabilidades de mais 
Risco alto para reutilizar
“Quem foi o 
FDP que 
escreveu 
isso aqui?”
Refactoring
O que é mais caro?
O que é mais caro?
É melhor pagar sem 
juros, certo?
Não esqueça, 
Pague o débito!
Se vc não paga suas contas?
“Refactoring is a disciplined 
technique for restructuring an 
existing body of code, altering its 
internal structure without 
changing its external behavior.” 
Martin Fowler
By continuously improving the design of code, we 
make it easier and easier to work with. This is in 
sharp contrast to what typically happens: little 
refactoring and a great deal of attention paid to 
expediently adding new features. If you get into the 
hygienic habit of refactoring continuously, you'll 
find that it is easier to extend and maintain code. 
Joshua Kerievsky
Não deixe 
pra depois!
Baby Steps
BBAADD SSMMEELLLLSS
Sintomas de 
que seu 
código está 
com 
problemas.
Long Method 
The object programs that live best and longest are those with short 
methods. 
[…] 
The key here is not method length but the semantic distance 
between what the method does and how it does it. 
[…]
Long Method 
[…] 
Development environments that allow you to see two methods at 
once help to eliminate this step, but the real key to making it easy to 
understand small methods is good naming. 
[…]
public int fechaFolha(String folha) { 
// imprime a folha adicionando bla bla bla 
try { 
FileReader arq = new FileReader(folha); 
BufferedReader lerArq = new BufferedReader(arq); 
String linha = lerArq.readLine(); 
while (linha != null) { 
System.out.printf("%sn", linha); 
this.linha += linha; 
linha = lerArq.readLine(); 
} 
arq.close(); 
} catch (IOException e) { 
System.err.printf("Erro na abertura do arquivo: %s.n", 
e.getMessage()); 
} 
// verifica se a folha é especial 
if (linha.contains("ARS0010304")) { 
this.folhaEspecial = true; 
}
public int fechaFolha(String folha) { 
imprimeFolha(folha); 
ehFolhaEspecial(); 
atualizaDadosDePagamento(); 
}
public int fechaFolha(String folha) { 
imprimeFolha(folha); 
eFolhaEspecial(); 
atualizaDadosDePagamento(); 
} 
private void ehFolhaEspecial() { 
if (linha.contains("ARS0010304")) { 
this.folhaEspecial = true; 
} 
} 
private void imprimeFolha(String folha) { 
try { 
FileReader arq = new FileReader(folha); 
BufferedReader lerArq = new BufferedReader(arq); 
String linha = lerArq.readLine(); 
while (linha != null) { 
System.out.printf("%sn", linha); 
this.linha += linha; 
linha = lerArq.readLine(); 
}... 
I throw away 
commented code
Few Short Methods Per Class 
★ Fácil de testar. 
★ Fácil para reusar. 
★ Fácil para modificar. 
★ Menos bugs são descoberto, estatisticamente em métodos 
curtos e classes curtas. 
★ Equipe de desenvolvimento coda mais rápido, porque há menos 
necessidade de refactoring.
Shotgun Surgery
Shotgun Surgery 
You whiff this when every time you make a kind of change, you have 
to make a lot of little changes to a lot of different classes. When 
the changes are all over the place, they are hard to find, and it's 
easy to miss an important change.
Feature Envy 
FFeeaattuurree EEnnvvyy
Feature Envy 
A classic smell is a method that seems more interested in a class 
other than the one it actually is in. 
[ . . . ] 
The most common focus of the envy is the data.
Feature Envy 
Mova o método quando todo o método quer estar claramente em 
outro lugar, ou… 
Extraia o método quando apenas uma parte do método é invejoso, 
ou… 
Extraia a classe se você tem vários métodos invejosos e a 
funcionalidade não chega a pertencer a outro objeto.
Feature Envy
Long Parameter List 
public Object method(int var,int var1,int 
var2,int var3,int var4,int var5,int var6,int 
var7) { 
... 
}
Long Parameter List 
[…] 
long parameter lists are hard to understand, because they become 
inconsistent and difficult to use, and because you are forever 
changing them as you need more data. 
[…]
DDDDDuuuuupppppllllliiiiciccccaaaaattttteeeeeddddd CCCCCooooodddddeeeee
Duplicated Code
Duplicated Code
Duplicated Code 
Large Class 
Method 
Shotgun Surgery Long Parameter List 
Refused Bequest 
BBAADD SSMMDatEEa ClLaLssLLSS 
Comments Lazy Class 
Divergent Change 
Parallel Inheritance Hierarchies 
Switch Statements 
Primitive Obsession 
Data Clumps 
Feature 
Envy Incomplete Library Class 
Alternative Classes with Different Interfaces 
Inappropriate 
Intimacy 
Middle Man 
Message Chains 
Temporary Field 
Speculative Generality
RRRRRRRRReeeeeeeeefffffffffaaaaaaaaaccccccccctttttttttooooooooorrrrrrrrriiiiiiiininnnnnnnnggggggggg
Extract Method 
Motivation 
Extract Method is one of the most common refactorings I do. I look at a method that is too long or look at code 
that needs a comment to understand its purpose. I then turn that fragment of code into its own method. 
I prefer short, well-named methods for several reasons. First, it increases the chances that other methods can 
use a method when the method is finely grained. Second, it allows the higher-level methods to read more like a 
series of comments. Overriding also is easier when the methods are finely grained. 
It does take a little getting used to if you are used to seeing larger methods. And small methods really work only 
when you have good names, so you need to pay attention to naming. People sometimes ask me what length I 
look for in a method. To me length is not the issue. The key is the semantic distance between the method name 
and the method body. If extracting improves clarity, do it, even if the name is longer than the code you have 
extracted.
void printOwing() { 
Enumeration e = _orders.elements(); 
double outstanding = 0.0; 
System.out.println("**************************"); 
System.out.println("***** Customer Owes ******"); 
System.out.println("**************************"); 
while (e.hasMoreElements()) { 
Order each = (Order) e.nextElement(); 
outstanding += each.getAmount(); 
} 
System.out.println("name:" + _name); 
System.out.println("amount" + outstanding); 
}
void printOwing() { 
Enumeration e = _orders.elements(); 
double outstanding = 0.0; 
System.out.println("**************************"); 
System.out.println("***** Customer Owes ******"); 
System.out.println("**************************"); 
while (e.hasMoreElements()) { 
Order each = (Order) e.nextElement(); 
outstanding += each.getAmount(); 
} 
System.out.println("name:" + _name); 
System.out.println("amount" + outstanding); 
}
void printOwing() { 
Enumeration e = _orders.elements(); 
double outstanding = 0.0; 
System.out.println("**************************"); 
System.out.println("***** Customer Owes ******"); 
System.out.println("**************************"); 
while (e.hasMoreElements()) { 
Order each = (Order) e.nextElement(); 
outstanding += each.getAmount(); 
} 
System.out.println("name:" + _name); 
System.out.println("amount" + outstanding); 
} 
void printBanner() { 
System.out.println("**************************"); 
System.out.println("***** Customer Owes ******"); 
System.out.println("**************************"); 
}
void printOwing() { 
Enumeration e = _orders.elements(); 
double outstanding = 0.0; 
printBanner(); 
while (e.hasMoreElements()) { 
Order each = (Order) e.nextElement(); 
outstanding += each.getAmount(); 
} 
System.out.println("name:" + _name); 
System.out.println("amount" + outstanding); 
}
void printOwing() { 
Enumeration e = _orders.elements(); 
double outstanding = 0.0; 
System.out.println("**************************"); 
System.out.println("***** Customer Owes ******"); 
System.out.println("**************************"); 
while (e.hasMoreElements()) { 
Order each = (Order) e.nextElement(); 
outstanding += each.getAmount(); 
} 
System.out.println("name:" + _name); 
System.out.println("amount" + outstanding); 
} 
void printDetails(double outstanding) { 
System.out.println("name:" + _name); 
System.out.println("amount" + outstanding); 
}
void printOwing() { 
Enumeration e = _orders.elements(); 
double outstanding = 0.0; 
printBanner(); 
while (e.hasMoreElements()) { 
Order each = (Order) e.nextElement(); 
outstanding += each.getAmount(); 
} 
printDetails(outstanding); 
}
void printOwing() { 
Enumeration e = _orders.elements(); 
double outstanding = 0.0; 
printBanner(); 
while (e.hasMoreElements()) { 
Order each = (Order) e.nextElement(); 
outstanding += each.getAmount(); 
} 
printDetails(outstanding); 
}
void printOwing() { 
Enumeration e = _orders.elements(); 
double outstanding = 0.0; 
printBanner(); 
while (e.hasMoreElements()) { 
Order each = (Order) e.nextElement(); 
outstanding += each.getAmount(); 
} 
printDetails(outstanding); 
} 
double getOutstanding(double outstanding) { 
Enumeration e = _orders.elements(); 
double result = 0.0; 
while (e.hasMoreElements()) { 
Order each = (Order) e.nextElement(); 
result += each.getAmount(); 
} 
return result; 
}
void printOwing() { 
printBanner(); 
double outstanding = getOutstanding(); 
printDetails(outstanding); 
}
void printOwing() { 
printBanner(); 
double outstanding = getOutstanding(); 
printDetails(outstanding); 
} 
void printBanner() { 
System.out.println("**************************"); 
System.out.println("***** Customer Owes ******"); 
System.out.println("**************************"); 
} 
void printDetails(double outstanding) { 
System.out.println("name:" + _name); 
System.out.println("amount" + outstanding); 
} 
double getOutstanding(double outstanding)...
Replace Temp with Query 
Motivation 
The problem with temps is that they are temporary and local. Because they can be seen only in the context of 
the method in which they are used, temps tend to encourage longer methods, because that's the only way you 
can reach the temp. By replacing the temp with a query method, any method in the class can get at the 
information. That helps a lot in coming up with cleaner code for the class. 
Replace Temp with Query often is a vital step before Extract Method. Local variables make it difficult to extract, 
so replace as many variables as you can with queries. 
The straightforward cases of this refactoring are those in which temps are assigned only to once and those in 
which the expression that generates the assignment is free of side effects. Other cases are trickier but possible. 
You may need to use Split Temporary Variable or Separate Query from Modifier first to make things easier. If 
the temp is used to collect a result (such as summing over a loop), you need to copy some logic into the query 
method.
... 
double getPreco() { 
int precoBase = _quantidade * _precoDoItem; 
double fatorDeDesconto; 
if (precoBase > 1000) fatorDeDesconto = 0.95; 
else fatorDeDesconto = 0.98; 
return precoBase * fatorDeDesconto; 
} 
...
... 
double getPreco() { 
int precoBase = _quantidade * _precoDoItem; 
double fatorDeDesconto; 
if (precoBase > 1000) fatorDeDesconto = 0.95; 
else fatorDeDesconto = 0.98; 
return precoBase * fatorDeDesconto; 
} 
...
... 
double getPreco() { 
final int precoBase = _quantidade * _precoDoItem; 
final double fatorDeDesconto; 
if (precoBase > 1000) fatorDeDesconto = 0.95; 
else fatorDeDesconto = 0.98; 
return precoBase * fatorDeDesconto; 
} 
...
... 
double getPreco() { 
final int precoBase = precoBase(); 
final double fatorDeDesconto; 
if (precoBase > 1000) fatorDeDesconto = 0.95; 
else fatorDeDesconto = 0.98; 
return precoBase * fatorDeDesconto; 
} 
...
... 
double getPreco() { 
final int precoBase = precoBase(); 
final double fatorDeDesconto; 
if (precoBase > 1000) fatorDeDesconto = 0.95; 
else fatorDeDesconto = 0.98; 
return precoBase * fatorDeDesconto; 
} 
… 
private int precoBase() { 
return _quantidade * _precoDoItem; 
}
... 
double getPreco() { 
final int precoBase = precoBase(); 
final double fatorDeDesconto; 
if (precoBase > 1000) fatorDeDesconto = 0.95; 
else fatorDeDesconto = 0.98; 
return precoBase * fatorDeDesconto; 
} 
...
... 
double getPreco() { 
final int precoBase = precoBase(); 
final double fatorDeDesconto; 
if (precoBase() > 1000) fatorDeDesconto = 0.95; 
else fatorDeDesconto = 0.98; 
return precoBase * fatorDeDesconto; 
} 
...
... 
double getPreco() { 
final double fatorDeDesconto; 
if (precoBase() > 1000) fatorDeDesconto = 0.95; 
else fatorDeDesconto = 0.98; 
return precoBase * fatorDeDesconto; 
} 
...
... 
double getPreco() { 
final double fatorDeDesconto; 
if (precoBase() > 1000) fatorDeDesconto = 0.95; 
else fatorDeDesconto = 0.98; 
return precoBase * fatorDeDesconto; 
} 
... 
private double fatorDeDesconto() { 
if (precoBase() > 1000) return 0.95; 
else return 0.98; 
}
... 
double getPreco() { 
final double fatorDeDesconto = fatorDeDesconto(); 
if (precoBase() > 1000) fatorDeDesconto = 0.95; 
else fatorDeDesconto = 0.98; 
return precoBase * fatorDeDesconto; 
} 
...
... 
double getPreco() { 
final double fatorDeDesconto = fatorDeDesconto(); 
return precoBase() * fatorDeDesconto; 
} 
...
... 
double getPreco() { 
return precoBase() * fatorDeDesconto(); 
} 
...
... 
double getPreco() { 
return precoBase() * fatorDeDesconto(); 
} 
private int precoBase() { 
return _quantidade * _precoDoItem; 
} 
private double fatorDeDesconto() { 
if (precoBase() > 1000) return 0.95; 
else return 0.98; 
} 
...
... 
double getPreco() { 
int precoBase = _quantidade * _precoDoItem; 
double fatorDeDesconto; 
if (precoBase > 1000) fatorDeDesconto = 0.95; 
else fatorDeDesconto = 0.98; 
return precoBase * fatorDeDesconto; 
} 
...
double getPreco() { 
int pb = q * p; 
double fd; 
if (pb > 1000) fd = 0.95; 
else fd = 0.98; 
return pb * fd; 
}
double getPreco() { 
int pb = q * p; 
double fd; 
if (pb > 1000) fd = 0.95; 
else fd = 0.98; 
return pb * fd; 
} 
“Quem foi o FDP que 
escreveu isso aqui?”
Replace Conditional with Polymorphism 
Motivation 
One of the grandest sounding words in object jargon is polymorphism. The essence of polymorphsim is that it 
allows you to avoid writing an explicit conditional when you have objects whose behavior varies depending on 
their types. 
As a result you find that switch statements that switch on type codes or if-then-else statements that switch on 
type strings are much less common in an object-oriented program. 
Polymorphism gives you many advantages. The biggest gain occurs when this same set of conditions appears in 
many places in the program. If you want to add a new type, you have to find and update all the conditionals. 
But with subclasses you just create a new subclass and provide the appropriate methods. Clients of the class 
don't need to know about the subclasses, which reduces the dependencies in your system and makes it easier 
to update.
Replace Conditional with Polymorphism 
double getSpeed() { 
switch (_type) { 
case EUROPEAN: 
return getBaseSpeed(); 
case AFRICAN: 
return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts; 
case NORWEGIAN_BLUE: 
return (_isNailed) ? 0 : getBaseSpeed(_voltage); 
} 
throw new RuntimeException ("Should be unreachable"); 
}
Replace Conditional with Polymorphism
Replace Conditional with Polymorphism
public class Employee { 
private EmployeeType _type; 
int payAmount() { 
switch (getType()) { 
case EmployeeType.ENGINEER: 
return _monthlySalary; 
case EmployeeType.SALESMAN: 
return _monthlySalary + _commission; 
case EmployeeType.MANAGER: 
return _monthlySalary + _bonus; 
default: 
throw new RuntimeException("Incorrect Employee"); 
} 
} 
int getType() { 
return _type.getTypeCode(); 
}
public class Employee { 
private EmployeeType _type; 
int payAmount() { 
switch (getType()) { 
case EmployeeType.ENGINEER: 
return _monthlySalary; 
case EmployeeType.SALESMAN: 
return _monthlySalary + _commission; 
case EmployeeType.MANAGER: 
return _monthlySalary + _bonus; 
default: 
throw new RuntimeException("Incorrect Employee"); 
} 
} 
int getType() { 
return _type.getTypeCode(); 
}
public class Employee { 
private EmployeeType _type; 
int payAmount() { 
switch (getType()) { 
case EmployeeType.ENGINEER: 
return _monthlySalary; 
case EmployeeType.SALESMAN: 
return _monthlySalary + _commission; 
case EmployeeType.MANAGER: 
return _monthlySalary + _bonus; 
default: 
throw new RuntimeException("Incorrect Employee"); 
} 
} 
int getType() { 
return _type.getTypeCode(); 
}
public class Employee { 
private EmployeeType _type; 
int payAmount() { 
switch (getType()) { 
case EmployeeType.ENGINEER: 
return _monthlySalary; 
case EmployeeType.SALESMAN: 
return _monthlySalary + _commission; 
case EmployeeType.MANAGER: 
return _monthlySalary + _bonus; 
default: 
throw new RuntimeException("Incorrect Employee"); 
} 
} 
int getType() { 
return _type.getTypeCode(); 
} 
public int getMonthlySalary() { 
return _monthlySalary; 
} 
public int getCommission() { 
return _monthlySalary + _commission; 
} 
public int getBonus() { 
return _monthlySalary + _bonus; 
}
public class Employee { 
private EmployeeType _type; 
int payAmount() { 
switch (getType()) { 
case EmployeeType.ENGINEER: 
return _monthlySalary; 
case EmployeeType.SALESMAN: 
return _monthlySalary + _commission; 
case EmployeeType.MANAGER: 
return _monthlySalary + _bonus; 
default: 
throw new RuntimeException("Incorrect Employee"); 
} 
} 
int getType() { 
return _type.getTypeCode(); 
}
public class EmployeeType ... 
int payAmount(Employee emp) { 
switch (getTypeCode()) { 
case ENGINEER: 
return emp.getMonthlySalary(); 
case SALESMAN: 
return emp.getMonthlySalary() + emp.getCommission(); 
case MANAGER: 
return emp.getMonthlySalary() + emp.getBonus(); 
default: 
throw new RuntimeException("Incorrect Employee"); 
} 
} 
…
public class EmployeeType ... 
int payAmount(Employee emp) { 
switch (getTypeCode()) { 
case ENGINEER: 
return emp.getMonthlySalary(); 
case SALESMAN: 
return emp.getMonthlySalary() + emp.getCommission(); 
case MANAGER: 
return emp.getMonthlySalary() + emp.getBonus(); 
default: 
throw new RuntimeException("Incorrect Employee"); 
} 
} 
…
public class Employee { 
… 
int payAmount() { 
switch (getType()) { 
case EmployeeType.ENGINEER: 
return _monthlySalary; 
case EmployeeType.SALESMAN: 
return _monthlySalary + _commission; 
case EmployeeType.MANAGER: 
return _monthlySalary + _bonus; 
default: 
throw new RuntimeException("Incorrect Employee"); 
} 
} 
… 
}
public class Employee { 
… 
int payAmount() { 
return _type.payAmount(this); 
} 
… 
}
public class Salesman extends EmployeeType{ 
int payAmount(Employee emp) { 
return emp.getMonthlySalary() + emp.getCommission(); 
} 
… 
public class Manager extends EmployeeType { 
int payAmount(Employee emp) { 
return emp.getMonthlySalary() + emp.getBonus(); 
} 
…
Decompose Conditional 
Motivation 
One of the most common areas of complexity in a program lies in complex conditional logic. As you write code 
to test conditions and to do various things depending on various conditions, you quickly end up with a pretty 
long method. Length of a method is in itself a factor that makes it harder to read, but conditions increase the 
difficulty. The problem usually lies in the fact that the code, both in the condition checks and in the actions, tells 
you what happens but can easily obscure why it happens. 
As with any large block of code, you can make your intention clearer by decomposing it and replacing chunks of 
code with a method call named after the intention of that block of code. With conditions you can receive 
further benefit by doing this for the conditional part and each of the alternatives. This way you highlight the 
condition and make it clearly what you are branching on. You also highlight the reason for the branching.
Decompose Conditional 
if (date.before(SUMMER_START) || date.after(SUMMER_END)) 
charge = quantity * _winterRate + _winterServiceCharge; 
else 
charge = quantity * _summerRate;
Decompose Conditional 
if (date.before(SUMMER_START) || date.after(SUMMER_END)) 
charge = quantity * _winterRate + _winterServiceCharge; 
else 
charge = quantity * _summerRate;
Decompose Conditional 
private boolean notSummer(Date date) { 
return date.before (SUMMER_START) || date.after 
(SUMMER_END); 
if (date.before(SUMMER_START) || date.after(SUMMER_END)) 
charge = quantity * _winterRate + _winterServiceCharge; 
else 
charge = quantity * _summerRate; 
} 
private double summerCharge(int quantity) { 
return quantity * _summerRate; 
} 
private double winterCharge(int quantity) { 
return quantity * _winterRate + _winterServiceCharge; 
}
Decompose Conditional 
if (notSummer(date)) 
charge = winterCharge(quantity); 
else 
charge = summerCharge(quantity);
private boolean notSummer(Date date) { 
return date.before (SUMMER_START) || date.after(SUMMER_END); 
} 
private double summerCharge(int quantity) { 
return quantity * _summerRate; 
} 
private double winterCharge(int quantity) { 
return quantity * _winterRate + _winterServiceCharge; 
} 
Decompose Conditional
Tá funcionando então deixa!? 
The code "works", you know it works, 
but you need to refactor in order to put 
the code into a form you can understand 
and work with in order to extend its 
functionality.
Tá funcionando então deixa!? 
you write tests against the code, knowing 
that if the test fails, you wrote the test 
wrong. Don't change the code until you 
are confident you have enough tests to 
let you know if one of your refactorings 
broke something.
Using refactoring, 
the application design 
emerge according to 
its needs!
Não tenha medo 
de mudar, isto só 
perigoso quando 
você não tem 
testes de unidade 
automatizados!
… permita-se ser um 
profissional melhor… 
Use teste automatizados! 
@rponte 
Testes de unidade 
automatizados!
Projete para suas 
necessidades atuais, prever 
o futuro pode não ser a 
melhor opção. 
Se você não precisa, não 
faça! 
@OficialMaeDinah 
Eu sei fazer isso chapa, 
você não! Bjus ;***
https://twitter.com/OficialMaeDinah/status/58355091366871040
Se você não precisa, não faça!
Precisando de ajuda ???
FFFFiiiinnnniiiisssshhhh hhhhiiiimmmm !!!!!!!!
http://stateofagile.versionone.com/agile-practices-tools/
http://stateofagile.versionone.com/agile-practices-tools/
Unit Testing 
http://stateofagile.versionone.com/agile-practices-tools/
Refactoring 
http://stateofagile.versionone.com/agile-practices-tools/
TDD 
http://stateofagile.versionone.com/agile-practices-tools/
Collective Code 
Ownership 
http://stateofagile.versionone.com/agile-practices-tools/
Simplicidade
Simples é um adjetivo de dois gêneros e 
dois números, que descreve uma coisa 
que não é complicada, que não possui 
enfeites, ou que é clara, evidente ou 
natural. Também pode designar uma 
tarefa fácil de concretizar ou resolver 
(um problema de simples resolução).
Um projeto simples sempre leva menos 
tempo para terminar do que um problema 
complexo. Então, sempre faça a coisa mais 
simples que poderia funcionar em seguida. 
Se você encontrar algo que é complexo 
substituí-lo por algo simples. É sempre 
mais rápida e barata para substituir código 
complexo agora, antes de perder muito 
mais tempo com ela.
Um projeto simples sempre leva menos 
tempo para terminar do que um problema 
complexo. Então, sempre faça a coisa mais 
simples que poderia funcionar em seguida. 
Se você encontrar algo que é complexo 
substituí-lo por algo simples. É sempre 
mais rápida e barata para substituir código 
complexo agora, antes de perder muito 
mais tempo com ela.
Um projeto simples sempre leva menos 
tempo para terminar do que um problema 
complexo. Então, sempre faça a coisa mais 
simples que poderia funcionar em seguida. 
Se você encontrar algo que é complexo 
substituí-lo por algo simples. É sempre 
mais rápida e barata para substituir código 
complexo agora, antes de perder muito 
mais tempo com ela.
Manter as coisas o mais simples possível, 
desde que seja possível, nunca adicione 
funcionalidades antes de serem agendada. 
Cuidado, porém, manter um design simples 
é um trabalho difícil.
Manter as coisas o mais simples possível, 
desde que seja possível, nunca adicione 
funcionalidades antes de serem agendada. 
Cuidado, porém, manter um design simples 
é um trabalho difícil.
Simplicidade: a arte de maximizar a quantidade 
de trabalho que não precisou ser feito.
The Zen of Python 
Beautiful is better than ugly. 
Explicit is better than implicit. 
Simple is better than complex. 
Complex is better than complicated.
Livros
Links 
The principles of OOD ~ http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf 
Simplicity ~ http://www.extremeprogramming.org/rules/simple.html 
Refactoring ~ http://refactoring.com 
Refactoring to Patterns ~ http://goo.gl/k8fGol 
Bad Smells ~ http://sourcemaking.com/refactoring/bad-smells-in-code 
Cod Smells ~ http://c2.com/cgi/wiki?CodeSmell 
Using Good Naming To Detect Bad Code ~ http://c2.com/cgi/wiki?UsingGoodNamingToDetectBadCode 
Few Short Methods Per Class ~ http://c2.com/cgi/wiki?FewShortMethodsPerClass 
Refactoring Legacy Code ~ http://c2.com/cgi/wiki?RefactoringLegacyCode
Obrigado! 
Emanuel Canuto 
@emanuel_canuto 
emanuelcanuto@gmail.com 
http://emanuelcanuto.wordpress.com/

Mais conteúdo relacionado

Semelhante a Refactoring e Code Smells: Seu código está apodrecendo!

FME UC 2014: Keynote from Boundless
FME UC 2014: Keynote from BoundlessFME UC 2014: Keynote from Boundless
FME UC 2014: Keynote from BoundlessSafe Software
 
A gentle introduction to algorithm complexity analysis
A gentle introduction to algorithm complexity analysisA gentle introduction to algorithm complexity analysis
A gentle introduction to algorithm complexity analysisLewis Lin 🦊
 
Search and navigation in Visual Studio
Search and navigation in Visual StudioSearch and navigation in Visual Studio
Search and navigation in Visual StudioDavid Shepherd
 
The Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor correctionsThe Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor correctionsPhilip Schwarz
 
Android design patterns
Android design patternsAndroid design patterns
Android design patternsVitali Pekelis
 
The Sieve of Eratosthenes - Part 1
The Sieve of Eratosthenes - Part 1The Sieve of Eratosthenes - Part 1
The Sieve of Eratosthenes - Part 1Philip Schwarz
 
Basics of Programming - A Review Guide
Basics of Programming - A Review GuideBasics of Programming - A Review Guide
Basics of Programming - A Review GuideBenjamin Kissinger
 
Refactoring: Improve the design of existing code
Refactoring: Improve the design of existing codeRefactoring: Improve the design of existing code
Refactoring: Improve the design of existing codeValerio Maggio
 
Getting Unstuck: Working with Legacy Code and Data
Getting Unstuck: Working with Legacy Code and DataGetting Unstuck: Working with Legacy Code and Data
Getting Unstuck: Working with Legacy Code and DataCory Foy
 
Django tutorial
Django tutorialDjango tutorial
Django tutorialKsd Che
 
Evolve Your Code
Evolve Your CodeEvolve Your Code
Evolve Your CodeRookieOne
 
Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.
Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.
Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.Chris Laning
 
Code Review
Code ReviewCode Review
Code ReviewRavi Raj
 

Semelhante a Refactoring e Code Smells: Seu código está apodrecendo! (20)

FME UC 2014: Keynote from Boundless
FME UC 2014: Keynote from BoundlessFME UC 2014: Keynote from Boundless
FME UC 2014: Keynote from Boundless
 
Tic tac toe game code
Tic tac toe game codeTic tac toe game code
Tic tac toe game code
 
Tic tac toe
Tic tac toeTic tac toe
Tic tac toe
 
A gentle introduction to algorithm complexity analysis
A gentle introduction to algorithm complexity analysisA gentle introduction to algorithm complexity analysis
A gentle introduction to algorithm complexity analysis
 
Code Refactoring
Code RefactoringCode Refactoring
Code Refactoring
 
Search and navigation in Visual Studio
Search and navigation in Visual StudioSearch and navigation in Visual Studio
Search and navigation in Visual Studio
 
Design patterns
Design patternsDesign patterns
Design patterns
 
The Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor correctionsThe Sieve of Eratosthenes - Part 1 - with minor corrections
The Sieve of Eratosthenes - Part 1 - with minor corrections
 
Android design patterns
Android design patternsAndroid design patterns
Android design patterns
 
Debugging
DebuggingDebugging
Debugging
 
The Sieve of Eratosthenes - Part 1
The Sieve of Eratosthenes - Part 1The Sieve of Eratosthenes - Part 1
The Sieve of Eratosthenes - Part 1
 
Code Metrics
Code MetricsCode Metrics
Code Metrics
 
Basics of Programming - A Review Guide
Basics of Programming - A Review GuideBasics of Programming - A Review Guide
Basics of Programming - A Review Guide
 
Bad Smells in Code
Bad Smells in CodeBad Smells in Code
Bad Smells in Code
 
Refactoring: Improve the design of existing code
Refactoring: Improve the design of existing codeRefactoring: Improve the design of existing code
Refactoring: Improve the design of existing code
 
Getting Unstuck: Working with Legacy Code and Data
Getting Unstuck: Working with Legacy Code and DataGetting Unstuck: Working with Legacy Code and Data
Getting Unstuck: Working with Legacy Code and Data
 
Django tutorial
Django tutorialDjango tutorial
Django tutorial
 
Evolve Your Code
Evolve Your CodeEvolve Your Code
Evolve Your Code
 
Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.
Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.
Taming the Legacy Beast: Turning wild old code into a sleak new thoroughbread.
 
Code Review
Code ReviewCode Review
Code Review
 

Último

A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxComplianceQuest1
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...ICS
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)OPEN KNOWLEDGE GmbH
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfkalichargn70th171
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 

Último (20)

A Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docxA Secure and Reliable Document Management System is Essential.docx
A Secure and Reliable Document Management System is Essential.docx
 
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
The Real-World Challenges of Medical Device Cybersecurity- Mitigating Vulnera...
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)Der Spagat zwischen BIAS und FAIRNESS (2024)
Der Spagat zwischen BIAS und FAIRNESS (2024)
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 

Refactoring e Code Smells: Seu código está apodrecendo!

  • 1. Refactoring e Code Smells: Seu código está apodrecendo!
  • 2. Emanuel Canuto Desenvolvimento há 4 UECE Rock! Pensar Mantér a simplicidade Aprender @emanuel_canuto
  • 5.
  • 7. Tava precisando! @handersonbf https://www.facebook.com/photo.php?fbid=10203189806695222&set=p.10203189806695222&type=1&permPage=1
  • 10. Quem trabalha ou já trabalhou em algum projeto Bugado???
  • 11. Quem já bugou um projeto ???
  • 12. Pense! Quais foram as experiências ???
  • 13. Rigidez Parece simples, mas difícil de mudar Mudanças em cascata Dependências entre módulos Medo de correção de bugs
  • 14. Fragilidade Code and Fix Manutenção Adventure Desenvolvimento fora de controle Credibilidade começa a cair Terminei a feature!!! Ei mah, tua feature quebrou!
  • 15. Imobilidade Não é possível reutilizar software Muitas Dependências Responsabilidades de mais Risco alto para reutilizar
  • 16. “Quem foi o FDP que escreveu isso aqui?”
  • 18. O que é mais caro?
  • 19.
  • 20.
  • 21. O que é mais caro?
  • 22. É melhor pagar sem juros, certo?
  • 23. Não esqueça, Pague o débito!
  • 24. Se vc não paga suas contas?
  • 25. “Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior.” Martin Fowler
  • 26. By continuously improving the design of code, we make it easier and easier to work with. This is in sharp contrast to what typically happens: little refactoring and a great deal of attention paid to expediently adding new features. If you get into the hygienic habit of refactoring continuously, you'll find that it is easier to extend and maintain code. Joshua Kerievsky
  • 27. Não deixe pra depois!
  • 30. Sintomas de que seu código está com problemas.
  • 31. Long Method The object programs that live best and longest are those with short methods. […] The key here is not method length but the semantic distance between what the method does and how it does it. […]
  • 32. Long Method […] Development environments that allow you to see two methods at once help to eliminate this step, but the real key to making it easy to understand small methods is good naming. […]
  • 33. public int fechaFolha(String folha) { // imprime a folha adicionando bla bla bla try { FileReader arq = new FileReader(folha); BufferedReader lerArq = new BufferedReader(arq); String linha = lerArq.readLine(); while (linha != null) { System.out.printf("%sn", linha); this.linha += linha; linha = lerArq.readLine(); } arq.close(); } catch (IOException e) { System.err.printf("Erro na abertura do arquivo: %s.n", e.getMessage()); } // verifica se a folha é especial if (linha.contains("ARS0010304")) { this.folhaEspecial = true; }
  • 34. public int fechaFolha(String folha) { imprimeFolha(folha); ehFolhaEspecial(); atualizaDadosDePagamento(); }
  • 35. public int fechaFolha(String folha) { imprimeFolha(folha); eFolhaEspecial(); atualizaDadosDePagamento(); } private void ehFolhaEspecial() { if (linha.contains("ARS0010304")) { this.folhaEspecial = true; } } private void imprimeFolha(String folha) { try { FileReader arq = new FileReader(folha); BufferedReader lerArq = new BufferedReader(arq); String linha = lerArq.readLine(); while (linha != null) { System.out.printf("%sn", linha); this.linha += linha; linha = lerArq.readLine(); }... I throw away commented code
  • 36. Few Short Methods Per Class ★ Fácil de testar. ★ Fácil para reusar. ★ Fácil para modificar. ★ Menos bugs são descoberto, estatisticamente em métodos curtos e classes curtas. ★ Equipe de desenvolvimento coda mais rápido, porque há menos necessidade de refactoring.
  • 38.
  • 39.
  • 40. Shotgun Surgery You whiff this when every time you make a kind of change, you have to make a lot of little changes to a lot of different classes. When the changes are all over the place, they are hard to find, and it's easy to miss an important change.
  • 41.
  • 43. Feature Envy A classic smell is a method that seems more interested in a class other than the one it actually is in. [ . . . ] The most common focus of the envy is the data.
  • 44. Feature Envy Mova o método quando todo o método quer estar claramente em outro lugar, ou… Extraia o método quando apenas uma parte do método é invejoso, ou… Extraia a classe se você tem vários métodos invejosos e a funcionalidade não chega a pertencer a outro objeto.
  • 46. Long Parameter List public Object method(int var,int var1,int var2,int var3,int var4,int var5,int var6,int var7) { ... }
  • 47. Long Parameter List […] long parameter lists are hard to understand, because they become inconsistent and difficult to use, and because you are forever changing them as you need more data. […]
  • 51. Duplicated Code Large Class Method Shotgun Surgery Long Parameter List Refused Bequest BBAADD SSMMDatEEa ClLaLssLLSS Comments Lazy Class Divergent Change Parallel Inheritance Hierarchies Switch Statements Primitive Obsession Data Clumps Feature Envy Incomplete Library Class Alternative Classes with Different Interfaces Inappropriate Intimacy Middle Man Message Chains Temporary Field Speculative Generality
  • 53. Extract Method Motivation Extract Method is one of the most common refactorings I do. I look at a method that is too long or look at code that needs a comment to understand its purpose. I then turn that fragment of code into its own method. I prefer short, well-named methods for several reasons. First, it increases the chances that other methods can use a method when the method is finely grained. Second, it allows the higher-level methods to read more like a series of comments. Overriding also is easier when the methods are finely grained. It does take a little getting used to if you are used to seeing larger methods. And small methods really work only when you have good names, so you need to pay attention to naming. People sometimes ask me what length I look for in a method. To me length is not the issue. The key is the semantic distance between the method name and the method body. If extracting improves clarity, do it, even if the name is longer than the code you have extracted.
  • 54. void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; System.out.println("**************************"); System.out.println("***** Customer Owes ******"); System.out.println("**************************"); while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } System.out.println("name:" + _name); System.out.println("amount" + outstanding); }
  • 55. void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; System.out.println("**************************"); System.out.println("***** Customer Owes ******"); System.out.println("**************************"); while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } System.out.println("name:" + _name); System.out.println("amount" + outstanding); }
  • 56. void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; System.out.println("**************************"); System.out.println("***** Customer Owes ******"); System.out.println("**************************"); while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } System.out.println("name:" + _name); System.out.println("amount" + outstanding); } void printBanner() { System.out.println("**************************"); System.out.println("***** Customer Owes ******"); System.out.println("**************************"); }
  • 57. void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } System.out.println("name:" + _name); System.out.println("amount" + outstanding); }
  • 58. void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; System.out.println("**************************"); System.out.println("***** Customer Owes ******"); System.out.println("**************************"); while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } System.out.println("name:" + _name); System.out.println("amount" + outstanding); } void printDetails(double outstanding) { System.out.println("name:" + _name); System.out.println("amount" + outstanding); }
  • 59. void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } printDetails(outstanding); }
  • 60. void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } printDetails(outstanding); }
  • 61. void printOwing() { Enumeration e = _orders.elements(); double outstanding = 0.0; printBanner(); while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); outstanding += each.getAmount(); } printDetails(outstanding); } double getOutstanding(double outstanding) { Enumeration e = _orders.elements(); double result = 0.0; while (e.hasMoreElements()) { Order each = (Order) e.nextElement(); result += each.getAmount(); } return result; }
  • 62. void printOwing() { printBanner(); double outstanding = getOutstanding(); printDetails(outstanding); }
  • 63. void printOwing() { printBanner(); double outstanding = getOutstanding(); printDetails(outstanding); } void printBanner() { System.out.println("**************************"); System.out.println("***** Customer Owes ******"); System.out.println("**************************"); } void printDetails(double outstanding) { System.out.println("name:" + _name); System.out.println("amount" + outstanding); } double getOutstanding(double outstanding)...
  • 64. Replace Temp with Query Motivation The problem with temps is that they are temporary and local. Because they can be seen only in the context of the method in which they are used, temps tend to encourage longer methods, because that's the only way you can reach the temp. By replacing the temp with a query method, any method in the class can get at the information. That helps a lot in coming up with cleaner code for the class. Replace Temp with Query often is a vital step before Extract Method. Local variables make it difficult to extract, so replace as many variables as you can with queries. The straightforward cases of this refactoring are those in which temps are assigned only to once and those in which the expression that generates the assignment is free of side effects. Other cases are trickier but possible. You may need to use Split Temporary Variable or Separate Query from Modifier first to make things easier. If the temp is used to collect a result (such as summing over a loop), you need to copy some logic into the query method.
  • 65. ... double getPreco() { int precoBase = _quantidade * _precoDoItem; double fatorDeDesconto; if (precoBase > 1000) fatorDeDesconto = 0.95; else fatorDeDesconto = 0.98; return precoBase * fatorDeDesconto; } ...
  • 66. ... double getPreco() { int precoBase = _quantidade * _precoDoItem; double fatorDeDesconto; if (precoBase > 1000) fatorDeDesconto = 0.95; else fatorDeDesconto = 0.98; return precoBase * fatorDeDesconto; } ...
  • 67. ... double getPreco() { final int precoBase = _quantidade * _precoDoItem; final double fatorDeDesconto; if (precoBase > 1000) fatorDeDesconto = 0.95; else fatorDeDesconto = 0.98; return precoBase * fatorDeDesconto; } ...
  • 68. ... double getPreco() { final int precoBase = precoBase(); final double fatorDeDesconto; if (precoBase > 1000) fatorDeDesconto = 0.95; else fatorDeDesconto = 0.98; return precoBase * fatorDeDesconto; } ...
  • 69. ... double getPreco() { final int precoBase = precoBase(); final double fatorDeDesconto; if (precoBase > 1000) fatorDeDesconto = 0.95; else fatorDeDesconto = 0.98; return precoBase * fatorDeDesconto; } … private int precoBase() { return _quantidade * _precoDoItem; }
  • 70. ... double getPreco() { final int precoBase = precoBase(); final double fatorDeDesconto; if (precoBase > 1000) fatorDeDesconto = 0.95; else fatorDeDesconto = 0.98; return precoBase * fatorDeDesconto; } ...
  • 71. ... double getPreco() { final int precoBase = precoBase(); final double fatorDeDesconto; if (precoBase() > 1000) fatorDeDesconto = 0.95; else fatorDeDesconto = 0.98; return precoBase * fatorDeDesconto; } ...
  • 72. ... double getPreco() { final double fatorDeDesconto; if (precoBase() > 1000) fatorDeDesconto = 0.95; else fatorDeDesconto = 0.98; return precoBase * fatorDeDesconto; } ...
  • 73. ... double getPreco() { final double fatorDeDesconto; if (precoBase() > 1000) fatorDeDesconto = 0.95; else fatorDeDesconto = 0.98; return precoBase * fatorDeDesconto; } ... private double fatorDeDesconto() { if (precoBase() > 1000) return 0.95; else return 0.98; }
  • 74. ... double getPreco() { final double fatorDeDesconto = fatorDeDesconto(); if (precoBase() > 1000) fatorDeDesconto = 0.95; else fatorDeDesconto = 0.98; return precoBase * fatorDeDesconto; } ...
  • 75. ... double getPreco() { final double fatorDeDesconto = fatorDeDesconto(); return precoBase() * fatorDeDesconto; } ...
  • 76. ... double getPreco() { return precoBase() * fatorDeDesconto(); } ...
  • 77. ... double getPreco() { return precoBase() * fatorDeDesconto(); } private int precoBase() { return _quantidade * _precoDoItem; } private double fatorDeDesconto() { if (precoBase() > 1000) return 0.95; else return 0.98; } ...
  • 78. ... double getPreco() { int precoBase = _quantidade * _precoDoItem; double fatorDeDesconto; if (precoBase > 1000) fatorDeDesconto = 0.95; else fatorDeDesconto = 0.98; return precoBase * fatorDeDesconto; } ...
  • 79. double getPreco() { int pb = q * p; double fd; if (pb > 1000) fd = 0.95; else fd = 0.98; return pb * fd; }
  • 80. double getPreco() { int pb = q * p; double fd; if (pb > 1000) fd = 0.95; else fd = 0.98; return pb * fd; } “Quem foi o FDP que escreveu isso aqui?”
  • 81. Replace Conditional with Polymorphism Motivation One of the grandest sounding words in object jargon is polymorphism. The essence of polymorphsim is that it allows you to avoid writing an explicit conditional when you have objects whose behavior varies depending on their types. As a result you find that switch statements that switch on type codes or if-then-else statements that switch on type strings are much less common in an object-oriented program. Polymorphism gives you many advantages. The biggest gain occurs when this same set of conditions appears in many places in the program. If you want to add a new type, you have to find and update all the conditionals. But with subclasses you just create a new subclass and provide the appropriate methods. Clients of the class don't need to know about the subclasses, which reduces the dependencies in your system and makes it easier to update.
  • 82. Replace Conditional with Polymorphism double getSpeed() { switch (_type) { case EUROPEAN: return getBaseSpeed(); case AFRICAN: return getBaseSpeed() - getLoadFactor() * _numberOfCoconuts; case NORWEGIAN_BLUE: return (_isNailed) ? 0 : getBaseSpeed(_voltage); } throw new RuntimeException ("Should be unreachable"); }
  • 83. Replace Conditional with Polymorphism
  • 84. Replace Conditional with Polymorphism
  • 85. public class Employee { private EmployeeType _type; int payAmount() { switch (getType()) { case EmployeeType.ENGINEER: return _monthlySalary; case EmployeeType.SALESMAN: return _monthlySalary + _commission; case EmployeeType.MANAGER: return _monthlySalary + _bonus; default: throw new RuntimeException("Incorrect Employee"); } } int getType() { return _type.getTypeCode(); }
  • 86. public class Employee { private EmployeeType _type; int payAmount() { switch (getType()) { case EmployeeType.ENGINEER: return _monthlySalary; case EmployeeType.SALESMAN: return _monthlySalary + _commission; case EmployeeType.MANAGER: return _monthlySalary + _bonus; default: throw new RuntimeException("Incorrect Employee"); } } int getType() { return _type.getTypeCode(); }
  • 87. public class Employee { private EmployeeType _type; int payAmount() { switch (getType()) { case EmployeeType.ENGINEER: return _monthlySalary; case EmployeeType.SALESMAN: return _monthlySalary + _commission; case EmployeeType.MANAGER: return _monthlySalary + _bonus; default: throw new RuntimeException("Incorrect Employee"); } } int getType() { return _type.getTypeCode(); }
  • 88. public class Employee { private EmployeeType _type; int payAmount() { switch (getType()) { case EmployeeType.ENGINEER: return _monthlySalary; case EmployeeType.SALESMAN: return _monthlySalary + _commission; case EmployeeType.MANAGER: return _monthlySalary + _bonus; default: throw new RuntimeException("Incorrect Employee"); } } int getType() { return _type.getTypeCode(); } public int getMonthlySalary() { return _monthlySalary; } public int getCommission() { return _monthlySalary + _commission; } public int getBonus() { return _monthlySalary + _bonus; }
  • 89. public class Employee { private EmployeeType _type; int payAmount() { switch (getType()) { case EmployeeType.ENGINEER: return _monthlySalary; case EmployeeType.SALESMAN: return _monthlySalary + _commission; case EmployeeType.MANAGER: return _monthlySalary + _bonus; default: throw new RuntimeException("Incorrect Employee"); } } int getType() { return _type.getTypeCode(); }
  • 90. public class EmployeeType ... int payAmount(Employee emp) { switch (getTypeCode()) { case ENGINEER: return emp.getMonthlySalary(); case SALESMAN: return emp.getMonthlySalary() + emp.getCommission(); case MANAGER: return emp.getMonthlySalary() + emp.getBonus(); default: throw new RuntimeException("Incorrect Employee"); } } …
  • 91. public class EmployeeType ... int payAmount(Employee emp) { switch (getTypeCode()) { case ENGINEER: return emp.getMonthlySalary(); case SALESMAN: return emp.getMonthlySalary() + emp.getCommission(); case MANAGER: return emp.getMonthlySalary() + emp.getBonus(); default: throw new RuntimeException("Incorrect Employee"); } } …
  • 92. public class Employee { … int payAmount() { switch (getType()) { case EmployeeType.ENGINEER: return _monthlySalary; case EmployeeType.SALESMAN: return _monthlySalary + _commission; case EmployeeType.MANAGER: return _monthlySalary + _bonus; default: throw new RuntimeException("Incorrect Employee"); } } … }
  • 93. public class Employee { … int payAmount() { return _type.payAmount(this); } … }
  • 94. public class Salesman extends EmployeeType{ int payAmount(Employee emp) { return emp.getMonthlySalary() + emp.getCommission(); } … public class Manager extends EmployeeType { int payAmount(Employee emp) { return emp.getMonthlySalary() + emp.getBonus(); } …
  • 95. Decompose Conditional Motivation One of the most common areas of complexity in a program lies in complex conditional logic. As you write code to test conditions and to do various things depending on various conditions, you quickly end up with a pretty long method. Length of a method is in itself a factor that makes it harder to read, but conditions increase the difficulty. The problem usually lies in the fact that the code, both in the condition checks and in the actions, tells you what happens but can easily obscure why it happens. As with any large block of code, you can make your intention clearer by decomposing it and replacing chunks of code with a method call named after the intention of that block of code. With conditions you can receive further benefit by doing this for the conditional part and each of the alternatives. This way you highlight the condition and make it clearly what you are branching on. You also highlight the reason for the branching.
  • 96. Decompose Conditional if (date.before(SUMMER_START) || date.after(SUMMER_END)) charge = quantity * _winterRate + _winterServiceCharge; else charge = quantity * _summerRate;
  • 97. Decompose Conditional if (date.before(SUMMER_START) || date.after(SUMMER_END)) charge = quantity * _winterRate + _winterServiceCharge; else charge = quantity * _summerRate;
  • 98. Decompose Conditional private boolean notSummer(Date date) { return date.before (SUMMER_START) || date.after (SUMMER_END); if (date.before(SUMMER_START) || date.after(SUMMER_END)) charge = quantity * _winterRate + _winterServiceCharge; else charge = quantity * _summerRate; } private double summerCharge(int quantity) { return quantity * _summerRate; } private double winterCharge(int quantity) { return quantity * _winterRate + _winterServiceCharge; }
  • 99. Decompose Conditional if (notSummer(date)) charge = winterCharge(quantity); else charge = summerCharge(quantity);
  • 100. private boolean notSummer(Date date) { return date.before (SUMMER_START) || date.after(SUMMER_END); } private double summerCharge(int quantity) { return quantity * _summerRate; } private double winterCharge(int quantity) { return quantity * _winterRate + _winterServiceCharge; } Decompose Conditional
  • 101. Tá funcionando então deixa!? The code "works", you know it works, but you need to refactor in order to put the code into a form you can understand and work with in order to extend its functionality.
  • 102. Tá funcionando então deixa!? you write tests against the code, knowing that if the test fails, you wrote the test wrong. Don't change the code until you are confident you have enough tests to let you know if one of your refactorings broke something.
  • 103. Using refactoring, the application design emerge according to its needs!
  • 104. Não tenha medo de mudar, isto só perigoso quando você não tem testes de unidade automatizados!
  • 105. … permita-se ser um profissional melhor… Use teste automatizados! @rponte Testes de unidade automatizados!
  • 106. Projete para suas necessidades atuais, prever o futuro pode não ser a melhor opção. Se você não precisa, não faça! @OficialMaeDinah Eu sei fazer isso chapa, você não! Bjus ;***
  • 108. Se você não precisa, não faça!
  • 110.
  • 117. Collective Code Ownership http://stateofagile.versionone.com/agile-practices-tools/
  • 118.
  • 120. Simples é um adjetivo de dois gêneros e dois números, que descreve uma coisa que não é complicada, que não possui enfeites, ou que é clara, evidente ou natural. Também pode designar uma tarefa fácil de concretizar ou resolver (um problema de simples resolução).
  • 121. Um projeto simples sempre leva menos tempo para terminar do que um problema complexo. Então, sempre faça a coisa mais simples que poderia funcionar em seguida. Se você encontrar algo que é complexo substituí-lo por algo simples. É sempre mais rápida e barata para substituir código complexo agora, antes de perder muito mais tempo com ela.
  • 122. Um projeto simples sempre leva menos tempo para terminar do que um problema complexo. Então, sempre faça a coisa mais simples que poderia funcionar em seguida. Se você encontrar algo que é complexo substituí-lo por algo simples. É sempre mais rápida e barata para substituir código complexo agora, antes de perder muito mais tempo com ela.
  • 123. Um projeto simples sempre leva menos tempo para terminar do que um problema complexo. Então, sempre faça a coisa mais simples que poderia funcionar em seguida. Se você encontrar algo que é complexo substituí-lo por algo simples. É sempre mais rápida e barata para substituir código complexo agora, antes de perder muito mais tempo com ela.
  • 124. Manter as coisas o mais simples possível, desde que seja possível, nunca adicione funcionalidades antes de serem agendada. Cuidado, porém, manter um design simples é um trabalho difícil.
  • 125. Manter as coisas o mais simples possível, desde que seja possível, nunca adicione funcionalidades antes de serem agendada. Cuidado, porém, manter um design simples é um trabalho difícil.
  • 126. Simplicidade: a arte de maximizar a quantidade de trabalho que não precisou ser feito.
  • 127. The Zen of Python Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated.
  • 128. Livros
  • 129. Links The principles of OOD ~ http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf Simplicity ~ http://www.extremeprogramming.org/rules/simple.html Refactoring ~ http://refactoring.com Refactoring to Patterns ~ http://goo.gl/k8fGol Bad Smells ~ http://sourcemaking.com/refactoring/bad-smells-in-code Cod Smells ~ http://c2.com/cgi/wiki?CodeSmell Using Good Naming To Detect Bad Code ~ http://c2.com/cgi/wiki?UsingGoodNamingToDetectBadCode Few Short Methods Per Class ~ http://c2.com/cgi/wiki?FewShortMethodsPerClass Refactoring Legacy Code ~ http://c2.com/cgi/wiki?RefactoringLegacyCode
  • 130. Obrigado! Emanuel Canuto @emanuel_canuto emanuelcanuto@gmail.com http://emanuelcanuto.wordpress.com/