Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Elixir Brasil 2020 - Code Smells, Refactoring e Elixir

583e920a7e9238a1c21e923025f8f641?s=47 Elaine Naomi
November 29, 2020

Elixir Brasil 2020 - Code Smells, Refactoring e Elixir

583e920a7e9238a1c21e923025f8f641?s=128

Elaine Naomi

November 29, 2020
Tweet

Transcript

  1. Code Smells, Refatoração e Elixir uma conversa sobre qualidade de

    código
  2. Elaine Naomi Watanabe twitter.com/elaine_nw speakerdeck.com/elainenaomi Engenheira de Software (The RealReal)

    Mestrado em Ciência da Computação (USP) slides disponíveis
  3. therealreal.com/careers Referral Source Elaine Naomi Watanabe

  4. The RealReal - Elixir adoption story youtube.com/watch?v=sTs_4T1ufLY

  5. Sobre a Plataformatec...

  6. None
  7. o que aprontei por lá =) além de trabalhar como

    dev Sobre a Plataformatec... twitter.com/elaine_nw/status/1214748684593840128
  8. None
  9. REFATORAÇÃO

  10. REFATORAÇÃO + ELIXIR

  11. DEFINIÇÃO Code SMells Refatoração Na PRÁTICA Resumo e referências

  12. Code SMells DEFINIÇÃO Refatoração Na PRÁTICA Resumo e referências

  13. REFATORAÇÃO

  14. REFATORAÇÃO

  15. REFATORAÇÃO

  16. None
  17. None
  18. None
  19. None
  20. None
  21. código sendo refatorado falhando por dias?

  22. código sendo refatorado falhando por dias?

  23. código sendo refatorado falhando por dias? REFATORAÇÃO

  24. código sendo refatorado falhando por dias? REFATORAÇÃO

  25. Alteração da estrutura interna do código Tornar + fácil de

    ser compreendida Tornar + fácil de ser alterada Manter comportamento externo Refatoração Refactoring
  26. Refatoração Alteração da estrutura interna do código Tornar + fácil

    de ser compreendida Tornar + fácil de ser alterada Manter comportamento externo Refactoring
  27. Refatoração Alteração da estrutura interna do código Tornar + fácil

    de ser compreendida Tornar + fácil de ser alterada Manter comportamento externo Refactoring
  28. Refatoração Alteração da estrutura interna do código Tornar + fácil

    de ser compreendida Tornar + fácil de ser alterada Manter comportamento externo Refactoring
  29. Refatoração Alteração da estrutura interna do código Tornar + fácil

    de ser compreendida Tornar + fácil de ser alterada Manter comportamento externo Refactoring
  30. Refatoração Alteração da estrutura interna do código Tornar + fácil

    de ser compreendida Tornar + fácil de ser alterada Manter comportamento externo Refactoring
  31. RefatorAR Reestruturar um software Série de pequenas refatorações Manter o

    comportamento externo Refactoring
  32. RefatorAR Refactoring Reestruturar um software Série de pequenas refatorações Manter

    o comportamento externo
  33. RefatorAR Refactoring Reestruturar um software Série de pequenas refatorações Manter

    o comportamento externo
  34. RefatorAR Refactoring Reestruturar um software Série de pequenas refatorações Manter

    o comportamento externo
  35. RefatorAR Refactoring Reestruturar um software Série de pequenas refatorações Manter

    o comportamento externo
  36. Reestruturar um software Série de pequenas refatorações Manter o comportamento

    externo RefatorAR Refactoring não é qualquer limpeza de código
  37. Martin Fowler 1999

  38. Martin Fowler 1999

  39. 22 code smells 72 técnicas de refatoração 1999

  40. Martin Fowler 22 code smells 72 técnicas de refatoração 1999

  41. Martin Fowler 22 code smells 72 técnicas de refatoração 1999

  42. a partir de um sistema existente

  43. design/arquitetura + implementação a partir de um sistema existente

  44. design/arquitetura + implementação a partir de um sistema existente como

    alterar a estrutura do sistema
  45. design/arquitetura + implementação a partir de um sistema existente como

    alterar a estrutura do sistema detecção de code smells
  46. design/arquitetura + implementação detecção de code smells a partir de

    um sistema existente como alterar a estrutura do sistema + refatoração
  47. design/arquitetura + implementação detecção de code smells + refatoração a

    partir de um sistema existente como alterar a estrutura do sistema
  48. detecção de code smells + refatoração design/arquitetura + implementação a

    partir de um sistema existente como alterar a estrutura do sistema promover o redesign
  49. aperfeiçoar o design depois de escrito

  50. aperfeiçoar o design depois de escrito

  51. evolução contínua do design

  52. evolução contínua do design

  53. 2018 +18 anos depois 24 code smells 61 técnicas de

    refatoração
  54. 2018 +18 anos depois 24 code smells 61 técnicas de

    refatoração
  55. 2018 +18 anos depois 24 code smells 61 técnicas de

    refatoração
  56. 2018 +18 anos depois 24 code smells 61 técnicas de

    refatoração
  57. 2018 visão sobre mundo OO + funcional +18 anos depois

    24 code smells 61 técnicas de refatoração
  58. visão sobre mundo OO + funcional 2018 +18 anos depois

    24 code smells 61 técnicas de refatoração
  59. encapsulamento coesão composição polimorfismo 2018

  60. encapsulamento coesão composição polimorfismo 2018 em ambos paradigmas

  61. 2018 classes? objetos?

  62. modules maps e structs protocols behaviours metaprogramming 2018 classes? objetos?

  63. por que o design é importante?

  64. por que o design é importante?

  65. Do livro Refactoring DESIGN RUIM Funcionalidades acumuladas Tempo

  66. Do livro Refactoring Funcionalidades acumuladas Tempo DESIGN RUIM

  67. Entregas começam a atrasar Mais código para fazer as mesmas

    tarefas Pouco reúso de código Código difícil de entender Código difícil de alterar
  68. Entregas começam a atrasar Mais código para fazer as mesmas

    tarefas Pouco reúso de código Código difícil de entender Código difícil de alterar
  69. Entregas começam a atrasar Mais código para fazer as mesmas

    tarefas Pouco reúso de código Código difícil de entender Código difícil de alterar
  70. Entregas começam a atrasar Mais código para fazer as mesmas

    tarefas Pouco reúso de código Código difícil de entender Código difícil de alterar
  71. Entregas começam a atrasar Mais código para fazer as mesmas

    tarefas Pouco reúso de código Código difícil de entender Código difícil de alterar
  72. Entregas começam a atrasar Mais código para fazer as mesmas

    tarefas Pouco reúso de código Código difícil de entender Código difícil de alterar
  73. None
  74. pensando na evolutibilidade do software

  75. pensando na evolutibilidade do software

  76. pensando na evolutibilidade do software capacidade de adaptação ao longo

    do tempo
  77. o código será mais lido e modificado do que será

    escrito
  78. o código será mais lido e modificado do que será

    escrito
  79. o código será mais lido e modificado do que será

    escrito
  80. Do livro Refactoring DESIGN RUIM Hipótese da Estamina do Design

    (Design Stamina Hypothesis) DESIGN BOM Funcionalidades acumuladas Tempo
  81. Do livro Refactoring Hipótese da Estamina do Design (Design Stamina

    Hypothesis) DESIGN RUIM DESIGN BOM Funcionalidades acumuladas Tempo
  82. Código bem estruturado Fácil de entender Fácil de alterar Fácil

    de apagar
  83. Código bem estruturado Fácil de entender Fácil de alterar Fácil

    de apagar
  84. Código bem estruturado Fácil de entender Fácil de alterar Fácil

    de apagar
  85. Código bem estruturado Fácil de entender Fácil de alterar Fácil

    de apagar
  86. Código bem estruturado Fácil de entender Fácil de alterar Fácil

    de apagar
  87. Código bem estruturado Fácil de entender Fácil de alterar Fácil

    de apagar
  88. Código bem estruturado Fácil de entender Fácil de alterar Fácil

    de apagar spark joy
  89. None
  90. como identificar o que precisamos refatorar?

  91. como identificar o que precisamos refatorar?

  92. DEFINIÇÃO Code SMells Refatoração Na PRÁTICA Resumo e referências

  93. Code smells Características do código que normalmente indicam problemas de

    design mais profundos no sistema https://martinfowler.com/bliki/CodeSmell.html
  94. Code smells Características do código que normalmente indicam problemas de

    design mais profundos no sistema https://martinfowler.com/bliki/CodeSmell.html Também chamados de Bad Smells (maus cheiros)
  95. Code smells Características do código que normalmente indicam problemas de

    design mais profundos no sistema https://martinfowler.com/bliki/CodeSmell.html
  96. Code smells Características do código que normalmente indicam problemas de

    design mais profundos no sistema https://martinfowler.com/bliki/CodeSmell.html
  97. None
  98. None
  99. Código duplicado Duplicated Code

  100. Regra de negócio duplicada Texto duplicado

  101. Regra de negócio duplicada Texto duplicado

  102. defmodule CarrinhoCompra do # ... def calcular_frete(cep, assinatura) do if

    (Enum.member?([3, 4], assinatura.id)) do 0 else 10.0 * Localizacao.calcular(cep) end end def aplicar_desconto(total, assinatura) do if (Enum.member?([3, 4], assinatura.id)) do total * 0.9 else total end end end
  103. defmodule CarrinhoCompra do # ... def calcular_frete(cep, assinatura) do if

    (Enum.member?([3, 4], assinatura.id)) do 0 else 10.0 * Localizacao.calcular(cep) end end def aplicar_desconto(total, assinatura) do if (Enum.member?([3, 4], assinatura.id)) do total * 0.9 else total end end end
  104. defmodule CarrinhoCompra do # ... def calcular_frete(cep, assinatura) do if

    (Enum.member?([3, 4], assinatura.id)) do 0 else 10.0 * Localizacao.calcular(cep) end end def aplicar_desconto(total, assinatura) do if (Enum.member?([3, 4], assinatura.id)) do total * 0.9 else total end end end frete
  105. defmodule CarrinhoCompra do # ... def calcular_frete(cep, assinatura) do if

    (Enum.member?([3, 4], assinatura.id)) do 0 else 10.0 * Localizacao.calcular(cep) end end def aplicar_desconto(total, assinatura) do if (Enum.member?([3, 4], assinatura.id)) do total * 0.9 else total end end end desconto no valor total
  106. defmodule CarrinhoCompra do # ... def calcular_frete(cep, assinatura) do if

    (Enum.member?([3, 4], assinatura.id)) do 0 else 10.0 * Localizacao.calcular(cep) end end def aplicar_desconto(total, assinatura) do if (Enum.member?([3, 4], assinatura.id)) do total * 0.9 else total end end end contextos diferentes
  107. defmodule CarrinhoCompra do # ... def calcular_frete(cep, assinatura) do if

    (Enum.member?([3, 4], assinatura.id)) do 0 else 10.0 * Localizacao.calcular(cep) end end def aplicar_desconto(total, assinatura) do if (Enum.member?([3, 4], assinatura.id)) do total * 0.9 else total end end end que compartilham a mesma condicional
  108. mas cadê o pattern matching? =P

  109. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total end
  110. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total end pattern matching
  111. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total end frete
  112. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total end desconto no valor total
  113. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total end
  114. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total end código duplicado
  115. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total end regra de negócio misteriosa
  116. None
  117. cuidado com código que parece duplicado

  118. cuidado com código que parece duplicado

  119. precisamos entender o domínio para entender se as abstrações fazem

    sentido
  120. precisamos entender o domínio para entender se as abstrações fazem

    sentido
  121. Nome misterioso Mysterious Name

  122. defmodule Ordem do # ... def exec(i, d) do #

    ... end end
  123. defmodule Ordem do # ... def exec(i, d) do #

    ... end end
  124. defmodule Ordem do # ... def exec(i, d) do #

    ... end end o que são esses argumentos? o que eles representam?
  125. defmodule Ordem do # ... def exec(i, d) do #

    ... end end
  126. defmodule Ordem do # ... def exec(i, d) do #

    ... end end
  127. defmodule Ordem do # ... def exec(i, d) do #

    ... end end o que essa função faz?
  128. defmodule Ordem do # ... def exec(i, d) do i

    |> Enum.map(& &1.pco * &1.qtd) |> Enum.sum() |> Kernel.-(d) end end
  129. defmodule Ordem do # ... def exec(i, d) do i

    |> Enum.map(& &1.pco * &1.qtd) |> Enum.sum() |> Kernel.-(d) end end
  130. defmodule Ordem do # ... def exec(i, d) do i

    |> Enum.map(& &1.pco * &1.qtd) |> Enum.sum() |> Kernel.-(d) end end o que significam essas siglas?
  131. defmodule Ordem do # ... def exec(i, d) do i

    |> Enum.map(& &1.pco * &1.qtd) |> Enum.sum() |> Kernel.-(d) end end o que significam essas siglas?
  132. DAR NOMES é uma das duas coisas mais difíceis em

    computação https://martinfowler.com/bliki/TwoHardThings.html
  133. DAR NOMES é uma das duas coisas mais difíceis em

    computação https://martinfowler.com/bliki/TwoHardThings.html
  134. DAR NOMES é uma das duas coisas mais difíceis em

    computação https://martinfowler.com/bliki/TwoHardThings.html
  135. DAR NOMES é uma das duas coisas mais difíceis em

    computação https://martinfowler.com/bliki/TwoHardThings.html variáveis, funções, módulos devem representar o domínio de negócio
  136. DAR NOMES é uma das duas coisas mais difíceis em

    computação https://martinfowler.com/bliki/TwoHardThings.html variáveis, funções, módulos devem representar o domínio de negócio
  137. FunÇão Longa Long Function

  138. é uma função longa

  139. é uma função longa

  140. é uma função longa mas quão longa?

  141. defmodule Relatorio do def imprimir(usuario, pedido) do imprimir_dados_empresa() IO.puts("Nome: #{usuario.nome}

    #{usuario.sobrenome}") pedido.items |> Enum.filter(&(&1.status == 3)) |> Enum.map(fn item -> IO.puts("Item: #{item.nome}") IO.puts("Preço: #{item.preco}") IO.puts("Quantidade: #{item.quantidade}") total = item.preco * item.quantidade IO.puts("Total: #{total}") end) end end
  142. defmodule Relatorio do def imprimir(usuario, pedido) do imprimir_dados_empresa() IO.puts("Nome: #{usuario.nome}

    #{usuario.sobrenome}") pedido.items |> Enum.filter(&(&1.status == 3)) |> Enum.map(fn item -> IO.puts("Item: #{item.nome}") IO.puts("Preço: #{item.preco}") IO.puts("Quantidade: #{item.quantidade}") total = item.preco * item.quantidade IO.puts("Total: #{total}") end) end end
  143. defmodule Relatorio do def imprimir(usuario, pedido) do imprimir_dados_empresa() IO.puts("Nome: #{usuario.nome}

    #{usuario.sobrenome}") pedido.items |> Enum.filter(&(&1.status == 3)) |> Enum.map(fn item -> IO.puts("Item: #{item.nome}") IO.puts("Preço: #{item.preco}") IO.puts("Quantidade: #{item.quantidade}") total = item.preco * item.quantidade IO.puts("Total: #{total}") end) end end dados da empresa
  144. defmodule Relatorio do def imprimir(usuario, pedido) do imprimir_dados_empresa() IO.puts("Nome: #{usuario.nome}

    #{usuario.sobrenome}") pedido.items |> Enum.filter(&(&1.status == 3)) |> Enum.map(fn item -> IO.puts("Item: #{item.nome}") IO.puts("Preço: #{item.preco}") IO.puts("Quantidade: #{item.quantidade}") total = item.preco * item.quantidade IO.puts("Total: #{total}") end) end end dados do usuário
  145. defmodule Relatorio do def imprimir(usuario, pedido) do imprimir_dados_empresa() IO.puts("Nome: #{usuario.nome}

    #{usuario.sobrenome}") pedido.items |> Enum.filter(&(&1.status == 3)) |> Enum.map(fn item -> IO.puts("Item: #{item.nome}") IO.puts("Preço: #{item.preco}") IO.puts("Quantidade: #{item.quantidade}") total = item.preco * item.quantidade IO.puts("Total: #{total}") end) end end dados do pedido (com filtros e cálculos)
  146. Necessidade de separar blocos para entender Vontade de adicionar comentários

  147. Necessidade de separar blocos para entender Vontade de adicionar comentários

  148. Necessidade de separar blocos para entender Vontade de adicionar comentários

  149. Necessidade de separar blocos para entender Vontade de adicionar comentários

    que tal criar uma nova função?
  150. Classe Grande Long Class

  151. Classe Grande Long Class módulo

  152. Classe Grande Long Class módulo

  153. um módulo que faz muitas coisas, que cuida de várias

    regras de negócio
  154. um módulo que faz muitas coisas, que cuida de várias

    regras de negócio
  155. um módulo que faz muitas coisas, que cuida de várias

    regras de negócio
  156. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end
  157. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end versão com pattern matching
  158. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end cálculo de total de items
  159. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end cálculo de frete (com regras para assinaturas)
  160. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end cálculo de desconto (com regras para assinaturas)
  161. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end envio de email para upgrade de assinatura
  162. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end impressão dos dados do pedido
  163. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end o que esse módulo faz? -> total do pedido -> desconto para assinaturas -> frete de acordo com assinaturas -> email de upgrade de assinatura -> impressão
  164. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end o que esse módulo faz? -> total do pedido -> desconto para assinaturas -> frete de acordo com assinaturas -> email de upgrade de assinatura -> impressão
  165. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end o que esse módulo faz? -> total do pedido -> desconto para assinaturas -> frete de acordo com assinaturas -> email de upgrade de assinatura -> impressão
  166. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end o que esse módulo faz? -> total do pedido -> desconto para assinaturas -> frete de acordo com assinaturas -> email de upgrade de assinatura -> impressão
  167. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end o que esse módulo faz? -> total do pedido -> desconto para assinaturas -> frete de acordo com assinaturas -> email de upgrade de assinatura -> impressão
  168. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end o que esse módulo faz? -> total do pedido -> desconto para assinaturas -> frete de acordo com assinaturas -> email de upgrade de assinatura -> impressão
  169. defmodule CarrinhoCompra do def calcular_total(items, assinatura) do # ... end

    def calcular_frete(cep, %{id: 3}), do: 0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), do: total def mandar_mensagem_assinatura(%{id: 3}, _), do: nil def mandar_mensagem_assinatura(%{id: 4}, _), do: nil def mandar_mensagem_assinatura(assinatura, usuario), do: Assinatura.enviar_email_upgrade(assinatura, usuario) def imprimir(usuario, pedido) do # ... end end o que esse módulo faz? -> total do pedido -> desconto para assinaturas -> frete de acordo com assinaturas -> email de upgrade de assinatura -> impressão
  170. esses contextos poderiam estar em outros módulos

  171. Lista Longa de PArâmetros Long Parameter List

  172. defmodule Usuario do def criar_usuario(nome, email, senha, apelido, status, ativo,

    admin) do # ... end end
  173. defmodule Usuario do def criar_usuario(nome, email, senha, apelido, status, ativo,

    admin) do # ... end end
  174. defmodule Usuario do def criar_usuario( nome, email, senha, apelido, status,

    ativo, admin ) do # ... end end Usuario.criar_usuario/7
  175. Usuario.criar_usuario(

  176. Usuario.criar_usuario(

  177. defmodule Usuario do def criar_usuario( nome, email, senha, apelido, status,

    ativo, admin ) do # ... end end
  178. defmodule Usuario do def criar_usuario( nome, email, senha, apelido, status,

    ativo, admin ) do # ... end end
  179. defmodule Usuario do def criar_usuario( nome, email, senha, apelido, status,

    ativo, admin ) do # ... end end
  180. defmodule Usuario do def criar_usuario( nome, email, senha, apelido, status,

    ativo, admin ) do # ... end end
  181. defmodule Usuario do def criar_usuario( nome, email, senha, apelido, status,

    ativo, admin ) do # ... end end
  182. defmodule Usuario do def criar_usuario( nome, email, senha, apelido, status,

    ativo, admin ) do # ... end end
  183. defmodule Usuario do def criar_usuario( nome, email, senha, apelido, status,

    ativo, admin ) do # ... end end
  184. Usuario.criar_usuario("Elaine", nome

  185. Usuario.criar_usuario("Elaine", "teste@teste.com", nome email

  186. Usuario.criar_usuario("Elaine", "teste@teste.com", "senha", nome email senha

  187. Usuario.criar_usuario("Elaine", "teste@teste.com", "senha", "elainenaomi", nome email senha apelido

  188. Usuario.criar_usuario("Elaine", "teste@teste.com", "senha", "elainenaomi", 1, nome email senha apelido status

  189. Usuario.criar_usuario("Elaine", "teste@teste.com", "senha", "elainenaomi", 1, true, nome email senha apelido

    status ativo
  190. Usuario.criar_usuario("Elaine", "teste@teste.com", "senha", "elainenaomi", 1, true, false) nome email senha

    apelido status ativo admin
  191. status 1 - gratuito 2 - basico 3 - plus

    Usuario.criar_usuario("Elaine", "teste@teste.com", "senha", "elainenaomi", 1, true, false) nome email senha apelido status ativo admin
  192. defmodule Usuario do def criar_usuario( nome, email, senha, apelido, status,

    ativo, admin ) do # ... end end
  193. defmodule Usuario do def criar_usuario( nome, email, senha, apelido, status,

    ativo, admin, pais ) do # ... end end
  194. defmodule Usuario do def criar_usuario( nome, email, senha, apelido, status,

    ativo, admin, pais ) do # ... end end
  195. mais de três ou quatro parâmetros? provavelmente existe uma abstração

    que poderia ser criada
  196. mais de três ou quatro parâmetros? provavelmente existe uma abstração

    que poderia ser criada
  197. Inveja de recursos Feature Envy

  198. Acessa mais a dados de outros contextos do que de

    seu próprio contexto/módulo Violação do princípio Tell, don't ask Chamadas repetidas a outro módulo
  199. Acessa mais a dados de outros contextos do que de

    seu próprio contexto/módulo Violação do princípio Tell, don't ask Chamadas repetidas a outro módulo
  200. Acessa mais a dados de outros contextos do que de

    seu próprio contexto/módulo Violação do princípio Tell, don't ask Chamadas repetidas a outro módulo
  201. Acessa mais a dados de outros contextos do que de

    seu próprio contexto/módulo Violação do princípio Tell, don't ask Chamadas repetidas a outro módulo
  202. defmodule Pedido do # ... def calcula_total_item(id) do item =

    ItemPedido.buscar_item(id) total = (item.preco + item.impostos) * item.quantidade desconto = ItemPedido.buscar_desconto(item) unless is_nil(desconto) do total - total * desconto else total end end end
  203. defmodule Pedido do # ... def calcula_total_item(id) do item =

    ItemPedido.buscar_item(id) total = (item.preco + item.impostos) * item.quantidade desconto = ItemPedido.buscar_desconto(item) unless is_nil(desconto) do total - total * desconto else total end end end
  204. defmodule Pedido do # ... def calcula_total_item(id) do item =

    ItemPedido.buscar_item(id) total = (item.preco + item.impostos) * item.quantidade desconto = ItemPedido.buscar_desconto(item) unless is_nil(desconto) do total - total * desconto else total end end end
  205. defmodule Pedido do # ... def calcula_total_item(id) do item =

    ItemPedido.buscar_item(id) total = (item.preco + item.impostos) * item.quantidade desconto = ItemPedido.buscar_desconto(item) unless is_nil(desconto) do total - total * desconto else total end end end
  206. defmodule Pedido do # ... def calcula_total_item(id) do item =

    ItemPedido.buscar_item(id) total = (item.preco + item.impostos) * item.quantidade desconto = ItemPedido.buscar_desconto(item) unless is_nil(desconto) do total - total * desconto else total end end end
  207. defmodule Pedido do # ... def calcula_total_item(id) do item =

    ItemPedido.buscar_item(id) total = (item.preco + item.impostos) * item.quantidade desconto = ItemPedido.buscar_desconto(item) unless is_nil(desconto) do total - total * desconto else total end end end
  208. defmodule Pedido do # ... def calcula_total_item(id) do item =

    ItemPedido.buscar_item(id) total = (item.preco + item.impostos) * item.quantidade desconto = ItemPedido.buscar_desconto(item) unless is_nil(desconto) do total - total * desconto else total end end end nesse exemplo, todos os dados vêm de ItemPedido ItemPedido poderia encapsular essa regra
  209. Intimidade inapropriada Inappropriate Intimacy

  210. módulo ou função que conhece e pode alterar detalhes internos

    de outros módulos ou funções
  211. módulo ou função que conhece e pode alterar detalhes internos

    de outros módulos ou funções
  212. módulo ou função que conhece e pode alterar detalhes internos

    de outros módulos ou funções
  213. módulo ou função que conhece e pode alterar detalhes internos

    de outros módulos ou funções dentro do contexto de funções impuras
  214. defmodule Pedido do def cobrar(total, usuario) do cartao = Usuario.buscar_cartao_de_credito(usuario)

    if (cartao.status == 3) do gateway = Cartao.buscar_gateway_pagamento(cartao) Gateway.cobrar(gateway, cartao, total) end end end
  215. defmodule Pedido do def cobrar(total, usuario) do cartao = Usuario.buscar_cartao_de_credito(usuario)

    if (cartao.status == 3) do gateway = Cartao.buscar_gateway_pagamento(cartao) Gateway.cobrar(gateway, cartao, total) end end end
  216. defmodule Pedido do def cobrar(total, usuario) do cartao = Usuario.buscar_cartao_de_credito(usuario)

    if (cartao.status == 3) do gateway = Cartao.buscar_gateway_pagamento(cartao) Gateway.cobrar(gateway, cartao, total) end end end detalhes internos
  217. defmodule Pedido do def cobrar(total, usuario) do cartao = Usuario.buscar_cartao_de_credito(usuario)

    if (cartao.status == 3) do gateway = Cartao.buscar_gateway_pagamento(cartao) Gateway.cobrar(gateway, cartao, total) end end end
  218. defmodule Pedido do def cobrar(total, usuario) do cartao = Usuario.buscar_cartao_de_credito(usuario)

    if (cartao.status == 3) do gateway = Cartao.buscar_gateway_pagamento(cartao) Gateway.cobrar(gateway, cartao, total) end end end provavelmente essa regra deveria estar encapsulada
  219. Cirurgia com Rifle Shotgun Surgery

  220. None
  221. None
  222. None
  223. None
  224. None
  225. None
  226. é só um exemplo

  227. mas baseados em fatos reais

  228. mas baseados em fatos reais

  229. Mesma alteração em vários arquivos Buscas globais para toda alteração

  230. Mesma alteração em vários arquivos Buscas globais para toda alteração

  231. Mesma alteração em vários arquivos Buscas globais para toda alteração

  232. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), # sem desconto do: total end
  233. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), # sem desconto do: total end
  234. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), # sem desconto do: total end
  235. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), # sem desconto do: total end Enum.member?([3, 4], assinatura.id)
  236. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), # sem desconto do: total end Enum.member?([3, 4], assinatura.id)
  237. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), # sem desconto do: total end Enum.member?([3, 4, 8], assinatura.id)
  238. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), # sem desconto do: total end Enum.member?([3, 4, 8], assinatura.id)
  239. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, _), # sem desconto do: total end Enum.member?([3, 4, 8], assinatura.id) apenas seguindo o design...
  240. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, %{id: 8}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, %{id: 8}), do: total * 0.9 # ... end Enum.member?([3, 4, 8], assinatura.id)
  241. defmodule CarrinhoCompra do # ... def calcular_frete(cep, %{id: 3}), do:

    0.0 def calcular_frete(cep, %{id: 4}), do: 0.0 def calcular_frete(cep, %{id: 8}), do: 0.0 def calcular_frete(cep, _), do: 10.0 * Localizacao.calcular(cep) def aplicar_desconto(total, %{id: 3}), do: total * 0.9 def aplicar_desconto(total, %{id: 4}), do: total * 0.9 def aplicar_desconto(total, %{id: 8}), do: total * 0.9 # ... end Enum.member?([3, 4, 8], assinatura.id) e buscando outros lugares para alterar...
  242. defmodule Renovacao do def executar(%{id: id}, user) do case id

    do 3 -> Cobranca.cobrar(user, id, 100.0) 4 -> Cobranca.cobrar(user, id, 95.0) 2 -> Cobranca.cobrar(user, id, 50.0) end end end
  243. defmodule Renovacao do def executar(%{id: id}, user) do case id

    do 3 -> Cobranca.cobrar(user, id, 100.0) 4 -> Cobranca.cobrar(user, id, 95.0) 2 -> Cobranca.cobrar(user, id, 50.0) end end end
  244. defmodule Renovacao do def executar(%{id: id}, user) do case id

    do 3 -> Cobranca.cobrar(user, id, 100.0) 4 -> Cobranca.cobrar(user, id, 95.0) 8 -> Cobranca.cobrar(user, id, 90.0) 2 -> Cobranca.cobrar(user, id, 50.0) end end end
  245. defmodule Renovacao do def executar(%{id: id}, user) do case id

    do 3 -> Cobranca.cobrar(user, id, 100.0) 4 -> Cobranca.cobrar(user, id, 95.0) 8 -> Cobranca.cobrar(user, id, 90.0) 2 -> Cobranca.cobrar(user, id, 50.0) end end end
  246. Alteração Divergente Divergent Change

  247. defmodule Conta do # ... def logar_via_google(dados_google) do # ...

    end def logar_via_apple(dados_apple) do # ... end def cobrar_assinatura(assinatura) do # ... end def calcular_desconto_assinatura(assinatura) do # ... end end
  248. defmodule Conta do # ... def logar_via_google(dados_google) do # ...

    end def logar_via_apple(dados_apple) do # ... end def cobrar_assinatura(assinatura) do # ... end def calcular_desconto_assinatura(assinatura) do # ... end end
  249. defmodule Conta do # ... def logar_via_google(dados_google) do # ...

    end def logar_via_apple(dados_apple) do # ... end def cobrar_assinatura(assinatura) do # ... end def calcular_desconto_assinatura(assinatura) do # ... end end
  250. defmodule Conta do # ... def logar_via_google(dados_google) do # ...

    end def logar_via_apple(dados_apple) do # ... end def cobrar_assinatura(assinatura) do # ... end def calcular_desconto_assinatura(assinatura) do # ... end end mais de uma razão para mudar
  251. Módulo alterado constantemente Mudanças não relacionadas

  252. Módulo alterado constantemente Mudanças não relacionadas

  253. Módulo alterado constantemente Mudanças não relacionadas Provavelmente precisamos de novas

    abstrações
  254. Generalidade Especulativa Speculative Generalization

  255. campo, parâmetro, função ou módulo não utilizado

  256. campo, parâmetro, função ou módulo não utilizado

  257. campo, parâmetro, função ou módulo não utilizado adicionado para o

    futuro...
  258. defmodule Pessoa do def formatar_cpf(%{cpf: cpf}) do # ... end

    end
  259. defmodule PessoaFisica do def formatar_documento(%{cpf: cpf}) do # ... end

    end
  260. defmodule PessoaFisica do def formatar_documento(%{cpf: cpf}) do # ... end

    end defmodule PessoaJuridica do def formatar_documento(%{cnpj: cnpj}) do # ... end end
  261. defmodule PessoaFisica do def formatar_documento(%{cpf: cpf}) do # ... end

    end defmodule PessoaJuridica do def formatar_documento(%{cnpj: cnpj}) do # ... end end
  262. defmodule PessoaFisica do def formatar_documento(%{cpf: cpf}) do # ... end

    end defmodule PessoaJuridica do def formatar_documento(%{cnpj: cnpj}) do # ... end end utilizado em lugar nenhum nesse exemplo
  263. defmodule Assinatura do # ... def enviar_email(assinatura, true), do: Email.enviar_email_assinatura_ativa(assinatura)

    def enviar_email(assinatura, false), do: nil end
  264. defmodule Assinatura do # ... def enviar_email(assinatura, true), do: Email.enviar_email_assinatura_ativa(assinatura)

    def enviar_email(assinatura, false), do: nil end flag
  265. defmodule Assinatura do # ... def enviar_email(assinatura, true), do: Email.enviar_email_assinatura_ativa(assinatura)

    def enviar_email(assinatura, false), do: nil end sempre true...
  266. defmodule CarrinhoCompra do # ... def desconto_item(%{categoria: categoria} = produto)

    do case categoria do _ -> produto.desconto end end end
  267. defmodule CarrinhoCompra do # ... def desconto_item(%{categoria: categoria} = produto)

    do case categoria do _ -> produto.desconto end end end forçando um padrão
  268. defmodule CarrinhoCompra do # ... def desconto_item(%{categoria: categoria} = produto)

    do case categoria do _ -> produto.desconto end end end que não será utilizado
  269. módulos, funções, argumentos utilizados somente pelos casos de teste

  270. módulos, funções, argumentos utilizados somente pelos casos de teste

  271. Comentários Comments

  272. esse é polêmico

  273. qualquer comentário?

  274. é sobre comentários que explicam o que a função faz

  275. é sobre comentários que explicam o que a função faz

  276. defmodule Pedido do def cobrar(total, usuario) do cartao = Usuario.buscar_cartao_de_credito(usuario)

    # verifica se o cartão está ativo if (cartao.status == 3) do # ... end end end
  277. defmodule Pedido do def cobrar(total, usuario) do cartao = Usuario.buscar_cartao_de_credito(usuario)

    # verifica se o cartão está ativo if (cartao.status == 3) do # ... end end end
  278. e vale sempre lembrar

  279. comentário != documentação

  280. comentário != documentação

  281. doctests

  282. @doc """ Updates the `key` in `map` with the given

    function. If `key` is present in `map` then the existing value is passed to `fun` and its result is used as the updated value of `key`. If `key` is not present in `map`, `default` is inserted as the value of `key`. The default value will not be passed through the update function. ## Examples iex> Map.update(%{a: 1}, :a, 13, fn existing_value -> existing_value * 2 end) %{a: 2} iex> Map.update(%{a: 1}, :b, 11, fn existing_value -> existing_value * 2 end) %{a: 1, b: 11} """ @spec update(map, key, default :: value, (existing_value :: value -> updated_value :: value)) :: map def update(map, key, default, fun) when is_function(fun, 1) do # ...
  283. Agrupamento de dados (Data Clumps) Obsessão por primitivos (Primitive Obsession)

    Switches Repetidos (Repeated Switches) Campo temporário (Temporary Field) Cadeias de mensagens (Message Chains) Intermediário (Middle man) Outros code smells
  284. Trocas escusas (Insider Trading) Classes alternativas com interfaces diferentes (Alternative

    Classes with Different Interfaces) Classe de dados (Data Class) Herança recusada (Refused Bequest) Elemento ocioso (Lazy Element)
  285. Refatoração Na PRÁTICA DEFINIÇÃO Code SMells Resumo e referências

  286. None
  287. refatorar? detecção de Code Smell executar a refatoração fazer commit

    se sim compilar executar testes
  288. refatorar? detecção de Code Smell executar a refatoração fazer commit

    se sim compilar executar testes
  289. refatorar? detecção de Code Smell executar a refatoração fazer commit

    se sim compilar executar testes
  290. refatorar? detecção de Code Smell executar a refatoração fazer commit

    se sim compilar executar testes
  291. refatorar? detecção de Code Smell executar a refatoração fazer commit

    se sim compilar executar testes
  292. refatorar? detecção de Code Smell executar a refatoração fazer commit

    se sim compilar executar testes
  293. refatorar? detecção de Code Smell executar a refatoração fazer commit

    se sim compilar executar testes
  294. refatorar? detecção de Code Smell executar a refatoração fazer commit

    se sim compilar executar testes
  295. refatorar? detecção de Code Smell executar a refatoração fazer commit

    se sim compilar executar testes
  296. alguns exemplos de refatorações

  297. Renomear Variável Rename variable

  298. defmodule Ordem do # ... def exec(i, d) do #

    ... end end
  299. defmodule Ordem do # ... def exec(itens, desconto_total) do #

    ... end end
  300. defmodule Ordem do # ... def exec(itens, desconto_total) do #

    ... end end representações do contexto de negócio
  301. MUDAR DEClaraçÃo de Função Change Function Declaration

  302. defmodule Ordem do # ... def exec(itens, desconto_total) do #

    ... end end o que essa função faz?
  303. defmodule Ordem do # ... def calcular_total(itens, desconto_total) do #

    ... end end
  304. defmodule Assinatura do # ... def enviar_email(assinatura, true), do: Email.enviar_email_assinatura_ativa(assinatura)

    def enviar_email(assinatura, false), do: nil end
  305. defmodule Assinatura do # ... def enviar_email(assinatura), do: Email.enviar_email_assinatura_ativa(assinatura) end

    remover argumentos
  306. defmodule Assinatura do # ... def enviar_email(%Assinatura{} = assinatura), do:

    Email.enviar_email_assinatura_ativa(assinatura) end alterar assinatura da função
  307. Introduzir objeto de parâmetros Introduce Parameter Object

  308. abstração? módulo? struct? estrutura de dados? Introduzir objeto de parâmetros

    Introduce Parameter Object
  309. defmodule Relatorio do # ... def extrato_por_intervalo(inicio,fim) do # ...

    end end extrato_por_intervalo/2
  310. defmodule Relatorio do # ... def extrato_por_intervalo(intervalo) do # ...

    end end %{inicio: "2020-01-10", fim: "2020-02-10"} extrato_por_intervalo/1
  311. defmodule Relatorio do # ... def extrato_por_intervalo(%{ inicio: inicio, fim:

    fim }) do # ... end end extrato_por_intervalo/1 pattern matching
  312. defmodule Usuario do def criar_usuario( nome, email, senha, apelido, status,

    ativo, admin ) do # ... end end
  313. defmodule Usuario do def criar_usuario(user) do # ... end end

  314. defmodule Usuario do def criar_usuario(%Usuario{} = usuario) do # ...

    end end novo_usuario = %Usuario{ nome: "Elaine", email: "teste@teste.com", senha: "123", apelido: "elainenaomi", status: 1, ativo: true, admin: false } Usuario.criar_usuario(novo_usuario)
  315. REnomear campo Rename Field

  316. defmodule Ordem do # ... def calcular_total(itens, desconto_total) do items

    |> Enum.map(& &1.preco * &1.qtd) |> Enum.sum() |> Kernel.-(desconto) end end %{preco: 99.99, qtd: 1}
  317. defmodule Ordem do # ... def calcular_total(itens, desconto_total) do items

    |> Enum.map(& &1.preco * &1.quantidade) |> Enum.sum() |> Kernel.-(desconto) end end %{preco: 99.99, quantidade: 1}
  318. defmodule Ordem do # ... def calcular_total(itens, desconto_total) do items

    |> Enum.map(&calcular_total_item/1) |> Enum.sum() |> Kernel.-(desconto) end end Extrair função
  319. defmodule Ordem do # ... def calcular_total_item(%{qtd: _} = item),

    do: item.preco * item.qtd def calcular_total_item(item), do: item.preco * item.quantidade end campo legado (em migração)
  320. defmodule Ordem do # ... def calcular_total_item(%{qtd: _} = item),

    do: item.preco * item.qtd def calcular_total_item(item), do: item.preco * item.quantidade end novo campo
  321. defmodule Ordem do # ... def calcular_total(itens, desconto_total) do items

    |> Enum.map(& &1.preco * &1.qtd) |> Enum.sum() |> Kernel.-(desconto) end end %Ordem.ItemPedido {preco: 99.99, qtd: 1}
  322. defmodule Ordem.ItemPedido do @type t :: %__MODULE__{ id: String.t(), nome:

    String.t(), preco: Decimal.t(), qtd: integer() } defstruct id: nil, nome: nil, preco: nil, qtd: nil end
  323. defmodule Ordem.ItemPedido do @type t :: %__MODULE__{ id: String.t(), nome:

    String.t(), preco: Decimal.t(), quantidade: integer() } defstruct id: nil, nome: nil, preco: nil, quantidade: nil end
  324. defmodule Ordem.ItemPedido do @type t :: %__MODULE__{ id: String.t(), nome:

    String.t(), preco: Decimal.t(), quantidade: integer() } defstruct id: nil, nome: nil, preco: nil, quantidade: nil end compilador <3
  325. Extrair FUnção Extract Function

  326. defmodule Relatorio do def imprimir(usuario, pedido) do imprimir_dados_empresa() IO.puts("Nome: #{usuario.nome}")

    pedido.items |> Enum.filter(&(&1.status == 3)) |> Enum.map(fn item -> IO.puts("Item: #{item.nome}") IO.puts("Preço: #{item.preco}") IO.puts("Quantidade: #{item.quantidade}") total = item.preco * item.quantidade IO.puts("Total: #{total}") end) end end
  327. defmodule Relatorio do def imprimir(usuario, pedido) do imprimir_dados_empresa() IO.puts("Nome: #{usuario.nome}")

    pedido.items |> Enum.filter(&(&1.status == 3)) |> Enum.map(fn item -> IO.puts("Item: #{item.nome}") IO.puts("Preço: #{item.preco}") IO.puts("Quantidade: #{item.quantidade}") total = item.preco * item.quantidade IO.puts("Total: #{total}") end) end end
  328. defmodule Relatorio do def imprimir(usuario, pedido) do imprimir_dados_empresa() imprimir_dados_usuário(usuario) pedido.items

    |> Enum.filter(&(&1.status == 3)) |> Enum.map(fn item -> IO.puts("Item: #{item.nome}") IO.puts("Preço: #{item.preco}") IO.puts("Quantidade: #{item.quantidade}") total = item.preco * item.quantidade IO.puts("Total: #{total}") end) end end
  329. defmodule Relatorio do def imprimir(usuario, pedido) do imprimir_dados_empresa() imprimir_dados_usuário(usuario) pedido.items

    |> Enum.filter(&(&1.status == 3)) |> Enum.map(fn item -> IO.puts("Item: #{item.nome}") IO.puts("Preço: #{item.preco}") IO.puts("Quantidade: #{item.quantidade}") total = item.preco * item.quantidade IO.puts("Total: #{total}") end) end end
  330. defmodule Relatorio do def imprimir(usuario, pedido) do imprimir_dados_empresa() imprimir_dados_usuário(usuario) imprimir_dados_pedido(pedido)

    end # ... end
  331. Mover FunçÃO Move Function

  332. defmodule Pedido do # ... def calcula_total_item(id) do item =

    ItemPedido.buscar_item(id) total = (item.preco + item.impostos) * item.quantidade desconto = ItemPedido.buscar_desconto(item) unless is_nil(desconto) do total - total * desconto else total end end end
  333. defmodule Pedido do # ... def calcula_total_item(id) do item =

    ItemPedido.buscar_item(id) total = (item.preco + item.impostos) * item.quantidade desconto = ItemPedido.buscar_desconto(item) unless is_nil(desconto) do total - total * desconto else total end end end
  334. defmodule Pedido do # ... def calcula_total_item(id) do ItemPedido.calcular_valor_item(id) end

    end
  335. defmodule Pedido do # ... def calcula_total_item(id) do ItemPedido.calcular_valor_item(id) end

    end podem aparecer outros code smells nesse processo
  336. defmodule Pedido do # ... def calcula_total_item(id) do ItemPedido.calcular_valor_item(id) end

    end podem aparecer outros code smells nesse processo mas é só continuar o ciclo: refatorar, executar testes, fazer commit e reiniciar o processo
  337. Remover código morto Remove Dead Code

  338. defmodule CarrinhoCompras do def calcular_preco_total(item, _flag) do total = item.preco

    * item.quantidade if false do # desconto novo usuario total * 0.9 end total end end
  339. defmodule CarrinhoCompras do def calcular_preco_total(item, _flag) do total = item.preco

    * item.quantidade if false do # desconto novo usuario total * 0.9 end total end end
  340. defmodule CarrinhoCompras do def calcular_preco_total(item, _flag) do total = item.preco

    * item.quantidade if false do # desconto novo usuario total * 0.9 end total end end
  341. defmodule CarrinhoCompras do def calcular_preco_total(item, _flag) do total = item.preco

    * item.quantidade if false do # desconto novo usuario total * 0.9 end total end end
  342. defmodule CarrinhoCompras do def calcular_preco_total(item) do item.preco * item.quantidade end

    end
  343. Combinar Funções em Classe Combine Functions into Class

  344. Combinar Funções em Classe Combine Functions into Class módulo

  345. defmodule Conta do # ... def logar_via_google(dados_google) do # ...

    end def logar_via_apple(dados_apple) do # ... end def cobrar_assinatura(assinatura) do # ... end def calcular_desconto_assinatura(assinatura) do # ... end end
  346. defmodule Conta do # ... def logar_via_google(dados_google) do # ...

    end def logar_via_apple(dados_apple) do # ... end def cobrar_assinatura(assinatura) do # ... end def calcular_desconto_assinatura(assinatura) do # ... end end defmodule Login do # ... def logar_via_google(dados_google) do # ... end def logar_via_apple(dados_apple) do # ... end end novo módulo
  347. defmodule Conta do # ... def logar_via_google(dados_google) do # ...

    end def logar_via_apple(dados_apple) do # ... end def cobrar_assinatura(assinatura) do # ... end def calcular_desconto_assinatura(assinatura) do # ... end end
  348. defmodule Conta do # ... def logar_via_google(dados_google) do # ...

    end def logar_via_apple(dados_apple) do # ... end def cobrar_assinatura(assinatura) do # ... end def calcular_desconto_assinatura(assinatura) do # ... end end defmodule Assinatura do def cobrar_assinatura(assinatura) do # ... end def calcular_desconto_assinatura(assinatura) do # ... end end novo módulo
  349. defmodule Conta do # ... end defmodule Login do #

    ... end defmodule Assinatura do # ... end melhor isolamento dos domínios e regras de negócio
  350. Remover subclasse Remove subclass

  351. Remover subclasse Remove subclass subtipo

  352. Remover subclasse Remove subclass "submódulo"

  353. defmodule PessoaFisica do def formatar_documento(%{cpf: cpf}) do # ... end

    end defmodule PessoaJuridica do def formatar_documento(%{cnpj: cnpj}) do # ... end end
  354. defmodule PessoaFisica do def formatar_documento(%{cpf: cpf}) do # ... end

    end defmodule PessoaJuridica do def formatar_documento(%{cnpj: cnpj}) do # ... end end PessoaJuridica não é utilizado nesse exemplo
  355. defmodule PessoaFisica do def formatar_documento(%{cpf: cpf}) do # ... end

    end
  356. defmodule Pessoa do def formatar_documento(%{cpf: cpf}) do # ... end

    end módulo representando a linguagem do domínio se não existe pessoa jurídica, não faz sentido diferenciar pessoa física
  357. Substituir condicional por polimorfismo Replace Conditional With Polymorphism

  358. defmodule Relatorio do def enviar_relatorio(usuario, conteudo, tipo) do case tipo

    do :pdf -> PDF.criar(conteudo) :texto -> Texto.gerar(conteudo, margin: false) _ -> nil end |> Email.enviar(usuario.email, conteudo) end end
  359. defmodule Relatorio do def enviar_relatorio(usuario, conteudo, tipo) do case tipo

    do :pdf -> PDF.criar(conteudo) :texto -> Texto.gerar(conteudo, margin: false) _ -> nil end |> Email.enviar(usuario.email, conteudo) end end
  360. defmodule Relatorio do def enviar_relatorio(usuario, conteudo, tipo) do case tipo

    do :pdf -> PDF.criar(conteudo) :texto -> Texto.gerar(conteudo, margin: false) _ -> nil end |> Email.enviar(usuario.email, conteudo) end end podemos definir uma interface
  361. usando protocols

  362. defprotocol Relatorio do def criar_arquivo(conteudo) end defimpl Relatorio, for: PDF

    do def criar_arquivo(linhas), do: PDF.criar(linhas) end defimpl Relatorio, for: Texto do def criar_arquivo(conteudo), do: Texto.exibir(conteudo) end
  363. defprotocol Relatorio do def criar_arquivo(conteudo) end defimpl Relatorio, for: PDF

    do def criar_arquivo(linhas), do: PDF.criar(linhas) end defimpl Relatorio, for: Texto do def criar_arquivo(conteudo), do: Texto.exibir(conteudo) end
  364. defprotocol Relatorio do def criar_arquivo(conteudo) end defimpl Relatorio, for: PDF

    do def criar_arquivo(linhas), do: PDF.criar(linhas) end defimpl Relatorio, for: Texto do def criar_arquivo(conteudo), do: Texto.exibir(conteudo) end
  365. defprotocol Relatorio do def criar_arquivo(conteudo) end defimpl Relatorio, for: PDF

    do def criar_arquivo(linhas), do: PDF.criar(linhas) end defimpl Relatorio, for: Texto do def criar_arquivo(conteudo), do: Texto.exibir(conteudo) end
  366. defmodule Relatorio do def enviar_relatorio(usuario, conteudo, tipo) do case tipo

    do :pdf -> PDF.criar(conteudo) :texto -> Texto.gerar(conteudo, margin: false) _ -> nil end |> Email.enviar(usuario.email, conteudo) end end
  367. defmodule Relatorio do def enviar_relatorio(usuario, conteudo) do conteudo |> Relatorio.criar_arquivo()

    |> Email.enviar(usuario.email, conteudo) end end
  368. Internalizar função (Inline Function) Extrair variável (Extract Variable) Internalizar variável

    (Inline Variable) Encapsular variável (Encapsulate Variable) Combinar funções em transformação (Combine Functions into Transform) Separar em fases (Split Phase) Encapsular registro (Encapsulate Record) Encapsular coleção (Encapsulate Collection) Substituir primitivo por objeto (Replace Primitive with Object) Substituir variável temporária por consulta (Replace Temp with Query) Internalizar classe (Inline Class) Ocultar delegação (Hide Delegate) Remover intermediário (Remove Middle Man) Outras refatorações
  369. Substituir algoritmo (Substitute Algorithm) Mover campo (Move Field) Mover instruções

    para uma função (Move statements into Function) Mover instruções para os pontos de chamada (Move Statements to Callers) Substituir código internalizado por chamada de função (Replace Inline Code with Function Call) Deslocar instruções (Slide Statements) Dividir laço (Split Loop) Substituir laço por pipeline (Replace Loop with Pipeline) Separar variável (Split Variable) Substituir variável derivada por consulta (Replace Derived Variable with Query) Mudar referência para valor (Change Reference to Value) Mudar valor para referência (Change Value to Reference) Decompor condicional (Decompose Conditional) Consolidar expressão condicional (Consolidate Conditional Expression) Substituir condicional aninhada por cláusulas de guarda (Replace Nested Conditional with Guard Clauses)
  370. Introduzir caso especial (Introduce Special Case) Introduzir asserção (Introduce Assertion)

    Separar consulta de modificador (Separate Query from Modifier) Parametrizar função (Parameterize Function) Remover argumento de flag (Remove Flag Argument) Preservar objeto inteiro (Preserve Whole Object) Substituir parâmetro por consulta (Replace Parameter with Query) Substituir consulta por parâmetro (Replace Query with Parameter) Remover método de escrita (Remove Setting Method) Substituir construtor por função de factory (Replace Constructor with Factory Function) Substituir função por comando (Replace Function with Command) Substituir comando por função (Replace Command with Function) Subir método (Pull Up Method) Subir campo (Pull Up Field) Subir corpo do construtor (Pull Up Constructor Body)
  371. Extrair superclasse (Extract Superclass) Substituir subclasse por delegação (Replace Subclass

    with Delegate) Substituir superclasse por delegação (Replace Superclass with Delegate) Descer método (Push Down Method) Descer campo (Push Down Field) Substituir código de tipos por subclasses (Replace Type Code with Subclasses)
  372. None
  373. Coesão Encapsulamento Acoplamento Abstração de Tipos

  374. Coesão Encapsulamento Acoplamento Abstração de Tipos uma lista dos principais

    objetivos no processo de refatoração
  375. não esqueçam da importância dos testes

  376. não esqueçam da importância dos testes

  377. ciclo contínuo de feedback

  378. ciclo contínuo de feedback

  379. e ferramentas podem auxiliar nesse processo

  380. hexdocs.pm/credo

  381. refatoração, identificação de bugs, consistência de código, etc

  382. DEFINIÇÃO Code SMells Refatoração Na PRÁTICA Resumo e referências

  383. None
  384. DESIGN DE CÓDIGO sobre a estrutura do código sobre abstrações

    do domínio e regras de negócio sobre código fácil de ser compreendido e alterado sobre como as abstrações interagem entre si
  385. DESIGN DE CÓDIGO sobre a estrutura do código sobre abstrações

    do domínio e regras de negócio sobre código fácil de ser compreendido e alterado sobre como as abstrações interagem entre si
  386. DESIGN DE CÓDIGO sobre a estrutura do código sobre abstrações

    do domínio e regras de negócio sobre código fácil de ser compreendido e alterado sobre como as abstrações interagem entre si
  387. DESIGN DE CÓDIGO sobre a estrutura do código sobre abstrações

    do domínio e regras de negócio sobre código fácil de ser compreendido e alterado sobre como as abstrações interagem entre si
  388. DESIGN DE CÓDIGO sobre a estrutura do código sobre abstrações

    do domínio e regras de negócio sobre código fácil de ser compreendido e alterado sobre como as abstrações interagem entre si
  389. DESIGN DE CÓDIGO sobre a estrutura do código sobre abstrações

    do domínio e regras de negócio sobre código fácil de ser compreendido e alterado sobre como as abstrações interagem entre si
  390. apontam possíveis problemas de design alertam sobre redução da qualidade

    indicam possível impacto no negócio CODE SMELLS
  391. apontam possíveis problemas de design alertam sobre redução da qualidade

    indicam possível impacto no negócio CODE SMELLS
  392. apontam possíveis problemas de design alertam sobre redução da qualidade

    indicam possível impacto no negócio CODE SMELLS
  393. apontam possíveis problemas de design alertam sobre redução da qualidade

    indicam possível impacto no negócio CODE SMELLS
  394. apontam possíveis problemas de design alertam sobre redução da qualidade

    indicam possível impacto no negócio CODE SMELLS
  395. REFATORAÇÃO

  396. reorganização contínua do código

  397. reorganização contínua do código

  398. é sobre identificação de code smells e possíveis refatorações

  399. é sobre identificação de code smells e possíveis refatorações

  400. é sobre pequenas mudanças

  401. é sobre pequenas mudanças

  402. é sobre evoluir o design do código de maneira saudável

  403. é sobre evoluir o design do código de maneira saudável

  404. revisão de código por pares pode ser uma parte importante

    desse processo
  405. revisão de código por pares pode ser uma parte importante

    desse processo
  406. https://sourcelevel.io/code-review-ebook

  407. None
  408. refatoração != revolução

  409. refatoração != revolução

  410. não é para refatorar só porque existe um code smell

  411. ou tratar todo code smell como um falso positivo

  412. precisamos olhar para o código que deixamos como legado

  413. precisamos olhar para o código que deixamos como legado

  414. converse com seu time sobre a importância da qualidade do

    código
  415. converse com seu time sobre a importância da qualidade do

    código
  416. analisem juntos os trade-offs

  417. analisem juntos os trade-offs

  418. negociar quando refatorar faz parte do processo

  419. negociar quando refatorar faz parte do processo

  420. cuidado com big design up front e overengineering

  421. cuidado com big design up front e overengineering

  422. e não esqueçam:

  423. codar é um processo de comunicação

  424. codar é um processo de comunicação

  425. escrevemos código para pessoas, não para máquinas

  426. escrevemos código para pessoas, não para máquinas

  427. Mais sobre qualidade de código? Design de código, SOLID Padrões

    de projeto TDD, DDD, Agile
  428. Mais sobre qualidade de software? Design de código, SOLID Padrões

    de projeto TDD, DDD, Agile
  429. minhas referências

  430. None
  431. Functional Design Patterns - Scott Wlaschin https://youtu.be/srQt1NAHYC0 Refactoring Elixir -

    Lessons Learned from a Year on Exercism.Io - Devon Estes https://youtu.be/tJJMrtJEK1A Refactoring Techniques for Elixir, Ecto, and Phoenix - Gary Rennie https://youtu.be/V21DAKtY31Q Using Credo to improve your Elixir code - Vitali Tatarintev https://whatdidilearn.info/2018/05/27/using-credo-to-improve-your-elixir-code.html Protocols Are Powerful but Beware - Timmon Verlaan https://timmo.immo/blog/protocols-beware Polymorphism in Elixir - Mustafa Turan https://medium.com/elixirlabs/polymorphism-in-elixir-cd0c765b6929
  432. None
  433. None
  434. None
  435. None
  436. All the Little Things - Sandi Metz https://youtu.be/8bZh5LMaSmE Evitando o

    Jenga Driven Development - João Britto https://pt-br.eventials.com/locaweb/evitando-o-jenga-driven-development-com-joao-britto/ How Elixir made me a better Java programmer - Juliana Helena https://youtu.be/O86LQ58PvKU Arquitetura Hexagonal: mantendo sua aplicação saudável por Camila Campos https://youtu.be/mYWG8Qv8W5k Encontrando equilíbrio do DDD enquanto sua aplicação cresce - Carol Karklis https://pt.slideshare.net/CarolinaKarklisPacke/encontrando-equilbrio-do-ddd-enquanto-sua -aplicao-cresce
  437. None
  438. None
  439. None
  440. None
  441. None
  442. thoughtbot.com/upcase/clean-code refactoring.guru elixirschool.com refactoring.com/catalog Mais referências

  443. Exercism.io become a mentor https://exercism.io/become-a-mentor

  444. None
  445. None
  446. None
  447. None
  448. espero conhecer vocês pessoalmente ano que vem

  449. speakerdeck.com/elainenaomi elainenaomi.dev Inveja de Recursos (Feature Envy) Muito obrigada

  450. ilustrações do undraw.co