Refatoração
Aquela caprichada no código
@jucycabrera
Juciellen
Cabrera
@jucycabrera
Mãe de um menino inteligente
Carregando mais um bebezinho
PHPWomen / Imoye
Passo frio na Irlanda
Adoro comida, memes e fofoca
Software Engineer na Smartbox Group
Por que raios gostamos de refatorar?
Uma mudança feita na estrutura interna do
software o tornando mais compreensível e menos
custoso de alterá-lo sem mudar seu
comportamento observável.
Refatoração (noun) Um erro comum é enxergar refatoração como uma ação
para corrigir problemas do passado ou remover um
código feio.
A ideia de construir uma aplicação que
não sofrerá alterações não é verdade na
maioria dos casos.
As pessoas alteram o código para atingir objetivos a
curto prazo, muitas vezes sem entender a
arquitetura da aplicação como um todo, dessa
forma o código perde sua estrutura. Perda de
estrutura tem um efeito acumulativo.
Você vai se perceber refatorando código
feio, mas um código bonito também precisa
ser refatorado.
Um código bem testado não apenas
permite refatoração, mas também
possibilita que novas funcionalidades
sejam adicionadas de forma mais segura,
já que qualquer possível bug criado com
a nova funcionalidade pode ser
facilmente encontrado e corrigido.
Um lembrete:
Bad Smells
Maus cheiros
Nome misterioso
Quando você não consegue pensar num bom nome para algo
talvez isso seja um sinal de um problema maior.
Código duplicado
Toda vez que você olhar pra essas duplicações você precisa
ler com cuidado para identificar a diferença.
Função longa
Quando maior for a função, mais difícil de entender
Classe grande
Uma classe com tanto código é uma péssima oportunidade
para código duplicado e caos.
Cirurgia de rifle
Toda vez que você muda algo, é necessário fazer uma
série de pequenas mudanças em várias classes diferentes.
Longa lista de parâmetros
Uma função que contém uma lista longa de argumentos
geralmente fica bem confusa
Obsessão por primitivos
Às vezes tipos primitivos, tais como inteiros, números com
pontos flutuantes e strings não representam o tipo de dados
com o qual se está lidando.
Generalidade Especulativa
Coisas criadas antes de serem necessárias
● Classe abstrata sem utilidade
● Delegação desnecessária
● Funções com argumentos nunca usados
Cadeia de mensagens
Grande linha de getThis().
Comentários
Quando você sente a necessidade de escrever um
comentário, primeiro tente refatorar o código de uma forma
de comentários se tornem desnecessários.
Polemic topic!
Lista de
Refatorações
Extrair função
Se você precisa se esforçar olhando um bloco de código
tentando entender a sua funcionalidade então você deveria
extrair funções.
Internalizar função
O contrário de extrair função, onde o corpo da função é tão
claro quanto o nome.
Extrair classe
Quando você se deparar com uma classe tão grande a ponto
de nao ser facilmente entendida você deveria considerar
onde ela pode ser dividida.
Internalizar classe
Quando não faz mais sentido determinada lógica estar
numa classe separada.
Ocultar delegação
Encapsulamento significa que módulos pouco precisam
saber de outras partes do sistema.
Lei de Demeter (Não fale com estranhos)
Remover intermediário
O contrário de ocultar delegação.
Extrair variável
Dar nome a uma expressão complexa e complicada de ler
Internalizar variável
Quando a variável não diz mais que a própria expressão.
Named properties
PHP 8
Mudar declaração de função | Renomear método
Um bom nome permite que se entenda o propósito da função quando você
vê ela sendo invocada.
Renomear variável
Nomear bem as coisas é o coração da programação clara.
Renomear campos
Nomes de campos são importantes principalmente quando esses são muito
utilizados na aplicação.
Encapsular Collection
A manipulação de uma collection deve ser encapsulada.
Introduzir objeto de parâmetros
Grupos de dados que costumam estar juntos pode ser substituído por uma
estrutura de dados.
Substituir primitivo por objeto
Exemplo: Número de telefone, valor monetário
Preservar objeto inteiro
Ao invés de passar vários valores de um objeto como argumento, pode-se
passar o objeto inteiro.
Substituir algoritmo
● Extrair métodos
● Criar um algoritmo mais simples
● Usar uma função nativa.
Mover função | Mover campo
Mover a função ou campo para um nível acima ou até
mesmo entre classes
Deslocar instruções
Um código é mais legível quando as coisas correlacionadas
aparecem juntas.
Dividir Loop
Dessa forma você garante que precisa entender uma coisa
por vez
Separe refatoração de
otimização
$averageAge = 0;
$totalSalary = 0;
foreach ($people as $person) {
$averageAge += $person->page;
$totalSalary += $person->salary;
}
$averageAge = $averageAge / count($people);
$averageAge = 0;
$totalSalary = 0;
foreach ($people as $person) {
$averageAge += $person->page;
}
foreach ($people as $person) {
$totalSalary += $person->salary;
}
$averageAge = $averageAge / count($people);
Remover código morto
Comentar código desnecessário é um hábito comum.
Apaga sem dó, git pra que não é mesmo?
Decompor conditional
Aplicar “Extrair função” na condição e em cada parte dela.
if ($date->before(SUMMER_START) || $date->after(SUMMER_END)) {
$charge = $quantity * $winterRate + $winterServiceCharge;
} else {
$charge = $quantity * $summerRate;
}
if (isSummer($date)) {
$charge = summerCharge($quantity);
} else {
$charge = winterCharge($quantity);
}
Substituir condicional aninhada por cláusulas de guarda
Invertendo as condições por exemplo
function getPayAmount() {
if ($this->isDead) {
$result = $this->deadAmount();
} else {
if ($this->isSeparated) {
$result = $this->separatedAmount();
} else {
if ($this->isRetired) {
$result = $this->retiredAmount();
} else {
$result = $this->normalPayAmount();
}
}
}
return $result;
}
function getPayAmount() {
if ($this->isDead) {
return $this->deadAmount();
}
if ($this->isSeparated) {
return $this->separatedAmount();
}
if ($this->isRetired) {
return $this->retiredAmount();
}
return $this->normalPayAmount();
}
Substituir condicional por polimorfismo
Criar subclasses para cada ramificação da estrutura condicional.
abstract class Bird {
// ...
abstract function getSpeed();
// ...
}
class European extends Bird {
public function getSpeed() {
return $this->getBaseSpeed();
}
}
class African extends Bird {
public function getSpeed() {
return $this->getBaseSpeed() -
$this->getLoadFactor() *
$this->numberOfCoconuts;
}
}
class NorwegianBlue extends Bird {
public function getSpeed() {
return ($this->isNailed) ? 0 :
$this->getBaseSpeed($this->voltage);
}
}
// Somewhere in Client code.
$speed = $bird->getSpeed();
class Bird {
// ...
public function getSpeed() {
switch ($this->type) {
case EUROPEAN:
return $this->getBaseSpeed();
case AFRICAN:
return $this->getBaseSpeed() - $this->getLoadFactor() *
$this->numberOfCoconuts;
case NORWEGIAN_BLUE:
return ($this->isNailed) ? 0 :
$this->getBaseSpeed($this->voltage);
}
throw new Exception("Should be unreachable");
}
// ...
}
Separar consulta de modificador
O famoso caso do findAndDoSomethingElse.
Uma função que retorna um valor não deveria sofrer efeitos colaterais.
Parametrizar função
Funções de lógica semelhante com valores diferentes podem ser
substituídas por uma única função com parâmetro.
Remover argumento de flag
Casos onde uma flag é usada para indicar qual lógica a função vai executar.
Fica mais mais claro criar funções explícitas para cada tarefa.
Substituir construtor por uma factory
Criando um único ponto onde a classe é instanciada, evita alto acoplamento.
class Employee {
// ...
public function __construct($type)
{
$this->type = $type;
}
// ...
}
class Employee {
// ...
static public function
create($type) {
$employee = new Employee($type);
// do some heavy lifting.
return $employee;
}
// ...
}
Extrair super classe
Subir método
Subir campo
Descer método
Descer campo
Lidando com herança
O segredo de uma refatoração
eficaz é reconhecer que você vai
mais rápido quando você dá passos
pequenos.
Martin Fowler
Dicas
Fique de olho nas atualizações
Crie testes
Passos pequenos
Não perca a chance de melhorar o código
Code review é uma oportunidade
para se discutir mudanças
Mais conteúdo
by Martin Fowler, with Kent Beck
2018 - 2nd edition
https://martinfowler.com/books/refactoring.html
Refactoring
Improving the Design of Existing Code
https://refactoring.guru
Obrigada
E bora refatorar
@jucycabrera

Refatoração - aquela caprichada no código

  • 1.
  • 2.
    Juciellen Cabrera @jucycabrera Mãe de ummenino inteligente Carregando mais um bebezinho PHPWomen / Imoye Passo frio na Irlanda Adoro comida, memes e fofoca Software Engineer na Smartbox Group
  • 3.
    Por que raiosgostamos de refatorar?
  • 4.
    Uma mudança feitana estrutura interna do software o tornando mais compreensível e menos custoso de alterá-lo sem mudar seu comportamento observável. Refatoração (noun) Um erro comum é enxergar refatoração como uma ação para corrigir problemas do passado ou remover um código feio.
  • 5.
    A ideia deconstruir uma aplicação que não sofrerá alterações não é verdade na maioria dos casos. As pessoas alteram o código para atingir objetivos a curto prazo, muitas vezes sem entender a arquitetura da aplicação como um todo, dessa forma o código perde sua estrutura. Perda de estrutura tem um efeito acumulativo. Você vai se perceber refatorando código feio, mas um código bonito também precisa ser refatorado.
  • 6.
    Um código bemtestado não apenas permite refatoração, mas também possibilita que novas funcionalidades sejam adicionadas de forma mais segura, já que qualquer possível bug criado com a nova funcionalidade pode ser facilmente encontrado e corrigido. Um lembrete:
  • 7.
  • 8.
    Nome misterioso Quando vocênão consegue pensar num bom nome para algo talvez isso seja um sinal de um problema maior.
  • 9.
    Código duplicado Toda vezque você olhar pra essas duplicações você precisa ler com cuidado para identificar a diferença.
  • 10.
    Função longa Quando maiorfor a função, mais difícil de entender Classe grande Uma classe com tanto código é uma péssima oportunidade para código duplicado e caos.
  • 11.
    Cirurgia de rifle Todavez que você muda algo, é necessário fazer uma série de pequenas mudanças em várias classes diferentes.
  • 12.
    Longa lista deparâmetros Uma função que contém uma lista longa de argumentos geralmente fica bem confusa Obsessão por primitivos Às vezes tipos primitivos, tais como inteiros, números com pontos flutuantes e strings não representam o tipo de dados com o qual se está lidando.
  • 13.
    Generalidade Especulativa Coisas criadasantes de serem necessárias ● Classe abstrata sem utilidade ● Delegação desnecessária ● Funções com argumentos nunca usados
  • 14.
    Cadeia de mensagens Grandelinha de getThis().
  • 15.
    Comentários Quando você sentea necessidade de escrever um comentário, primeiro tente refatorar o código de uma forma de comentários se tornem desnecessários. Polemic topic!
  • 16.
  • 17.
    Extrair função Se vocêprecisa se esforçar olhando um bloco de código tentando entender a sua funcionalidade então você deveria extrair funções. Internalizar função O contrário de extrair função, onde o corpo da função é tão claro quanto o nome.
  • 18.
    Extrair classe Quando vocêse deparar com uma classe tão grande a ponto de nao ser facilmente entendida você deveria considerar onde ela pode ser dividida. Internalizar classe Quando não faz mais sentido determinada lógica estar numa classe separada.
  • 19.
    Ocultar delegação Encapsulamento significaque módulos pouco precisam saber de outras partes do sistema. Lei de Demeter (Não fale com estranhos) Remover intermediário O contrário de ocultar delegação.
  • 20.
    Extrair variável Dar nomea uma expressão complexa e complicada de ler Internalizar variável Quando a variável não diz mais que a própria expressão. Named properties PHP 8
  • 21.
    Mudar declaração defunção | Renomear método Um bom nome permite que se entenda o propósito da função quando você vê ela sendo invocada. Renomear variável Nomear bem as coisas é o coração da programação clara. Renomear campos Nomes de campos são importantes principalmente quando esses são muito utilizados na aplicação.
  • 22.
    Encapsular Collection A manipulaçãode uma collection deve ser encapsulada.
  • 23.
    Introduzir objeto deparâmetros Grupos de dados que costumam estar juntos pode ser substituído por uma estrutura de dados. Substituir primitivo por objeto Exemplo: Número de telefone, valor monetário Preservar objeto inteiro Ao invés de passar vários valores de um objeto como argumento, pode-se passar o objeto inteiro.
  • 24.
    Substituir algoritmo ● Extrairmétodos ● Criar um algoritmo mais simples ● Usar uma função nativa.
  • 25.
    Mover função |Mover campo Mover a função ou campo para um nível acima ou até mesmo entre classes Deslocar instruções Um código é mais legível quando as coisas correlacionadas aparecem juntas.
  • 26.
    Dividir Loop Dessa formavocê garante que precisa entender uma coisa por vez Separe refatoração de otimização $averageAge = 0; $totalSalary = 0; foreach ($people as $person) { $averageAge += $person->page; $totalSalary += $person->salary; } $averageAge = $averageAge / count($people); $averageAge = 0; $totalSalary = 0; foreach ($people as $person) { $averageAge += $person->page; } foreach ($people as $person) { $totalSalary += $person->salary; } $averageAge = $averageAge / count($people);
  • 27.
    Remover código morto Comentarcódigo desnecessário é um hábito comum. Apaga sem dó, git pra que não é mesmo?
  • 28.
    Decompor conditional Aplicar “Extrairfunção” na condição e em cada parte dela. if ($date->before(SUMMER_START) || $date->after(SUMMER_END)) { $charge = $quantity * $winterRate + $winterServiceCharge; } else { $charge = $quantity * $summerRate; } if (isSummer($date)) { $charge = summerCharge($quantity); } else { $charge = winterCharge($quantity); }
  • 29.
    Substituir condicional aninhadapor cláusulas de guarda Invertendo as condições por exemplo function getPayAmount() { if ($this->isDead) { $result = $this->deadAmount(); } else { if ($this->isSeparated) { $result = $this->separatedAmount(); } else { if ($this->isRetired) { $result = $this->retiredAmount(); } else { $result = $this->normalPayAmount(); } } } return $result; } function getPayAmount() { if ($this->isDead) { return $this->deadAmount(); } if ($this->isSeparated) { return $this->separatedAmount(); } if ($this->isRetired) { return $this->retiredAmount(); } return $this->normalPayAmount(); }
  • 30.
    Substituir condicional porpolimorfismo Criar subclasses para cada ramificação da estrutura condicional. abstract class Bird { // ... abstract function getSpeed(); // ... } class European extends Bird { public function getSpeed() { return $this->getBaseSpeed(); } } class African extends Bird { public function getSpeed() { return $this->getBaseSpeed() - $this->getLoadFactor() * $this->numberOfCoconuts; } } class NorwegianBlue extends Bird { public function getSpeed() { return ($this->isNailed) ? 0 : $this->getBaseSpeed($this->voltage); } } // Somewhere in Client code. $speed = $bird->getSpeed(); class Bird { // ... public function getSpeed() { switch ($this->type) { case EUROPEAN: return $this->getBaseSpeed(); case AFRICAN: return $this->getBaseSpeed() - $this->getLoadFactor() * $this->numberOfCoconuts; case NORWEGIAN_BLUE: return ($this->isNailed) ? 0 : $this->getBaseSpeed($this->voltage); } throw new Exception("Should be unreachable"); } // ... }
  • 31.
    Separar consulta demodificador O famoso caso do findAndDoSomethingElse. Uma função que retorna um valor não deveria sofrer efeitos colaterais.
  • 32.
    Parametrizar função Funções delógica semelhante com valores diferentes podem ser substituídas por uma única função com parâmetro.
  • 33.
    Remover argumento deflag Casos onde uma flag é usada para indicar qual lógica a função vai executar. Fica mais mais claro criar funções explícitas para cada tarefa.
  • 34.
    Substituir construtor poruma factory Criando um único ponto onde a classe é instanciada, evita alto acoplamento. class Employee { // ... public function __construct($type) { $this->type = $type; } // ... } class Employee { // ... static public function create($type) { $employee = new Employee($type); // do some heavy lifting. return $employee; } // ... }
  • 35.
    Extrair super classe Subirmétodo Subir campo Descer método Descer campo Lidando com herança
  • 36.
    O segredo deuma refatoração eficaz é reconhecer que você vai mais rápido quando você dá passos pequenos. Martin Fowler
  • 37.
    Dicas Fique de olhonas atualizações Crie testes Passos pequenos Não perca a chance de melhorar o código Code review é uma oportunidade para se discutir mudanças
  • 38.
    Mais conteúdo by MartinFowler, with Kent Beck 2018 - 2nd edition https://martinfowler.com/books/refactoring.html Refactoring Improving the Design of Existing Code https://refactoring.guru
  • 39.