Skip to content

Instantly share code, notes, and snippets.

@lcezermf
Last active January 17, 2017 11:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lcezermf/291d47609f6ce1840a06b3edd8716651 to your computer and use it in GitHub Desktop.
Save lcezermf/291d47609f6ce1840a06b3edd8716651 to your computer and use it in GitHub Desktop.
Anotações - Refactoring

01 - Por onde começar um refactoring ?

  • Evite começar quebrando uma classe ou método grande já com a sua idéia de implementação final. Faça em partes.
  • "Faça funcionar, faça certo, melhore."
  • Idealmente quebre o código anteriomente grande em pequenas partes e vá refinando cada uma dessas pequenas partes, até chegar ao nível de ter refinado toda a classe ou método por completo.
  • Refatoração deve ser feita em pequenas partes para que bugs possam ser descobertos com mais facilidade e também para que seja mais fácil testar as pequenas partes.
  • Não exite em renomear coisas que façam sentido que sejam renomeadas.
  • Métodos devem pertercem ao objeto ao qual fazem mais uso dos dados, por exemplo se o método X do objeto N recebe um objeto O como argumento e dentro desse objeto O faz uso de dados de O, talvez faça mais sentido o método pertecer a classe O ao invés da classe N.

02 - Princípios da Refatoração

  • Quando estiver adicionando funcionalidades, apenas foque em adicionar e testar essas novas funcionalidades, não deve misturar essa atividade com refatoração.
  • O mesmo vale para o contrário, quando estiver fazendo refatoração, foque na reestruturação do comportamento já existente e não em adicionar novas funcionalidades.

Refatoração melhora o Design do Código

  • Quando código é feito ao longo do tempo e nunca é refatorado, ele degrada com o tempo, o que torna cada vez mais difícil ter clarezar de como está o design do código, se ele faz o que supostamente se propõe a fazer e se está fazendo do modo mais eficiente.
  • Quanto mais difícil de identificar o design do código, mais difícil é preserva-lo e mais rapidamente ele irá cair.
  • Quanto mais difícil, mais linhas de código, possívelmente bem a mais do que seria necessário para executar o código.
  • Utilizar refatoração para melhor código que seja estranho no primeiro momento, tornar aquele código desconhecido mais fácil de ser lido logo de cara

Refatorar para encontrar bugs

  • Tornar o código mais fácil, o torna mais fácil de testar e consequentemente encontrar mais bugs que podem ocorrer.

Regra de 3

  • Faça funcionar, faça certo, faça melhor.

Cuidado ao Refatorar

  • Não refatorar mais do que o necessário
  • Quando aprendemos uma nova técnica de refatoração é preciso saber que ela não se aplica a todas as situações
  • Cuidado a ao refatorar interfaces (métodos) públicos

BAD SMELLS

Duplication Code

  • Se o mesmo código é encontrado em dois ou mais métodos na mesma class, é possível utilizar a técnica Extract Method

  • Se o mesmo código é encontrado e duas subclasses de mesmo nível é possível subir para a superclasse o método ou atributos compartilhados pelo método.

  • Se a duplicação ocorre no construtor das subclasses também é possível mover para o construtor da superclasse

Sempre que possível tentar remover a duplicação o mais rápido possível, aplicando a melhor solução para cada caso onde ela pode ocorrer

Long Method

  • Classes com mais de 100 linhas são perigosas
  • Aplicar Extract Method ou Extract Class sempre que possível
  • Se a refatoração está complicada por conta de variáveis e muitos parâmetros, apicar Replace Temp With Query, Introduce Param Object e Preserve Whole Object.

Divergent Change

  • Ocorre quando ao precisar alterar um determinado método de uma classe, você acaba tendo que refatorar vários outros métodos dessa mesma classe, para que aquela alteração possa ser realizada.

  • As razões para isso ocorrer são códigos com arquitetura pobre.

  • Extract Class, Extract Superclass, Extract subclass podem resolver esse problema

Shotgun Surgery

  • Ocorre quando para realizar uma alteração em um método de determinada classe é preciso realizar várias alterações pequenas em outras classes que se relacionam com essa primeira.

  • O problema ocorrer por que uma determinada responsabilidade está espalhada por diversas classes.

  • Move Method ou Move Field

Feature Envy

  • O principal ponto sobre o uso da orientação a objetos é encapsular dados e comportamento para um objeto.
  • Um caso de uso clássico onde ocorre Feature Envy é quando determinado método está mais interessado em utilizar métodos ou atributos de outra class, mais do que a si mesmo.
  • Move Method e Extract Method podem ser utilizados para resolver o problema
  • Em alguns casos a classe que mantem o os dados da classe que mantem o comportamento é propositalmente separada, a vantagem de se utilizar dessa forma deixando a troca de comportamento transparente e dinâmica e quando se utilizam os padrões Visitor e Strategy.

Data Clumps

  • Grupo de parâmetros que está sendo usado em diferentes partes do software, como parâmetro de diferentes métodos, idealmente devem ser transformados em um único objeto.
  • Possível utilizar Param Object para grupar os atributos a um único objeto e preservar esse objeto para que ele seja utilizado como parâmetro.

Primitive Obsession

  • Ocorre quando se faz uso de algum tipo primitivo da linguagem para armazenar determinado grupo de informações, ao invés de se criar uma classe própria.

Case Statements

  • Evitar sempre que possível fazer case Statements no código, de preferência pelo uso de polimorfismo.

Parallel Inheritance Hierarchie

  • Ocorre toda vez que ao criar um determinada subclasse, outra subclasse também precisa ser criada.

Lazy Class

  • Classes que fazem pouco e podem ter seu comportamento inserido em outro lugar, ou classes não utilizadas devem ser apagadas. É possível utilizar Inline Class

Speculative Generality

  • Criar alguma classe/método para que ela possa ser usada em algum dia, porém esse dia nunca chega. Código acaba sobrando e apenas dificultando a leitura da classe ou do fluxo principal.

Message Chain

  • method.method_b.method_c.method_d -> Pode ser evitado com Delegators.

Middle Man

  • A classe possui poucos métodos e a maior parte de seu código é apenas para fazer delegações a outras classes, ela n deveria então existir.

Inappropriate Intimacy

  • Uma classe usa atributos e métodos privados de outra classe.

Data Class

  • Classes que servem apenas para armazenar dados e não tem nenhum comportamento atrelado, podem ser substituidas por uma Struct.

Refused Bequest

  • Similar ao ISP, sublclasses não devem herdar métodos que não irão usar. Quando superclasse e subclasses acabam servindo para propósitos bem diferentes, não fazendo sentido a herança.
### Extract Method Motivação: Melhora legibilidade, mantem os métodos pequenos obedecendo SRP, melhora manuteabilidade. - Antes ```ruby def print(amout) print_banner puts "name: #{@name}" puts "amount: #{amount}" end ``` - Depois ```ruby def print(amout) print_banner print_details(amount) end def print_banner; end def print_details(amount) puts "name: #{@name}" puts "amount: #{amount}" end ``` --- ### Inline Method Motivação: Não concordo. - Antes ```ruby def get_rating more_than_five_late_deliveries ? 2 : 1 end def more_than_five_late_deliveries @number_of_late_deliveries > 5 end ``` - Depois ```ruby def get_rating @number_of_late_deliveries > 5 ? 2 : 1 end ``` --- ### Inline Temp Motivação: Evitar uso de variáveis temporárias que armazenam valores ou expressões simples. - Antes ```ruby base_price = an_order.base_price return (base_price > 1000) ``` - Depois ```ruby return an_order.base_price > 1000 ``` --- #### Replace Temp with Query Motivação: Centraliza o valor da expressão em um método, facilitando reusabilidade de código e aumentando o SRP e coesão do método. - Antes ```ruby base_price = @quantity * @item_price if (base_price > 1000) base_price * 0.95 else base_price * 0.98 end ``` - Depois ```ruby if (base_price > 1000) base_price * 0.95 else base_price * 0.98 end def base_price @quantity * @item_price end ``` --- #### Replace Temp with Chain Motivação: Sempre que possível favorer o uso de cadeias de métodos, para dar maior fluência na leitura do fluxo - Antes ```ruby mock = Mock.new expectation = mock.expects(:a_method_name) expectation.with("arguments") expectation.returns([1, :array]) ``` - Depois ```ruby mock = Mock.new expectation = mock.expects(:a_method_name).with("arguments").returns([1, :array]) ``` --- #### Introduce explain Variable Motivação: Ao invés de fazer comparações ou verificações sobre valores soltos, dar um significado para esses valores. - Antes ```ruby if number =~ /\d+/ puts "NUMBER" end ``` - Depois ```ruby is_decimal = /\d+/ if number =~ is_decimal puts "NUMBER" end ``` ### Replace Method with Method Object Motivação: Você possui um método grande, que faz uso de muitas variáveis locais, de modo que n torna possível aplicar `Extract Method`. É possível transformar todo esse método em um objeto próprio, transformando essas variáveis locais em variáveis de instância desse objeto e decompondo ainda mais o método principais em métodos auxiliares.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment