$30 off During Our Annual Pro Sale. View Details »

Elixir Brasil 2020 - Code Smells, Refactoring e...

Elaine Naomi
November 29, 2020

Elixir Brasil 2020 - Code Smells, Refactoring e Elixir

Elaine Naomi

November 29, 2020
Tweet

More Decks by Elaine Naomi

Other Decks in Programming

Transcript

  1. o que aprontei por lá =) além de trabalhar como

    dev Sobre a Plataformatec... twitter.com/elaine_nw/status/1214748684593840128
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
  8. Reestruturar um software Série de pequenas refatorações Manter o comportamento

    externo RefatorAR Refactoring não é qualquer limpeza de código
  9. design/arquitetura + implementação a partir de um sistema existente como

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

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

    partir de um sistema existente como alterar a estrutura do sistema
  12. 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
  13. 2018 visão sobre mundo OO + funcional +18 anos depois

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

    24 code smells 61 técnicas de refatoração
  15. 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
  16. 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
  17. 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
  18. 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
  19. 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
  20. 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
  21. Do livro Refactoring DESIGN RUIM Hipótese da Estamina do Design

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

    Hypothesis) DESIGN RUIM DESIGN BOM Funcionalidades acumuladas Tempo
  23. Code smells Características do código que normalmente indicam problemas de

    design mais profundos no sistema https://martinfowler.com/bliki/CodeSmell.html
  24. 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)
  25. Code smells Características do código que normalmente indicam problemas de

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

    design mais profundos no sistema https://martinfowler.com/bliki/CodeSmell.html
  27. 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
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. defmodule Ordem do # ... def exec(i, d) do #

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

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

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

    |> Enum.map(& &1.pco * &1.qtd) |> Enum.sum() |> Kernel.-(d) end end
  44. 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?
  45. 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?
  46. DAR NOMES é uma das duas coisas mais difíceis em

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

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

    computação https://martinfowler.com/bliki/TwoHardThings.html
  49. 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
  50. 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
  51. 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
  52. 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
  53. 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
  54. 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
  55. 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)
  56. 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
  57. 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
  58. 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
  59. 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)
  60. 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)
  61. 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
  62. 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
  63. 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
  64. 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
  65. 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
  66. 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
  67. 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
  68. 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
  69. 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
  70. defmodule Usuario do def criar_usuario( nome, email, senha, apelido, status,

    ativo, admin ) do # ... end end Usuario.criar_usuario/7
  71. status 1 - gratuito 2 - basico 3 - plus

    Usuario.criar_usuario("Elaine", "[email protected]", "senha", "elainenaomi", 1, true, false) nome email senha apelido status ativo admin
  72. 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
  73. 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
  74. 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
  75. 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
  76. 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
  77. 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
  78. 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
  79. 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
  80. 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
  81. 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
  82. 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
  83. 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
  84. 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
  85. 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
  86. 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
  87. 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
  88. 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
  89. 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
  90. 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
  91. 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
  92. 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)
  93. 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)
  94. 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)
  95. 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)
  96. 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...
  97. 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)
  98. 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...
  99. 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
  100. 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
  101. 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
  102. 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
  103. 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
  104. 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
  105. 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
  106. 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
  107. defmodule PessoaFisica do def formatar_documento(%{cpf: cpf}) do # ... end

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

    end defmodule PessoaJuridica do def formatar_documento(%{cnpj: cnpj}) do # ... end end
  109. 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
  110. defmodule CarrinhoCompra do # ... def desconto_item(%{categoria: categoria} = produto)

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

    do case categoria do _ -> produto.desconto end end end que não será utilizado
  112. 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
  113. 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
  114. @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 # ...
  115. 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
  116. 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)
  117. defmodule Ordem do # ... def exec(itens, desconto_total) do #

    ... end end representações do contexto de negócio
  118. defmodule Assinatura do # ... def enviar_email(%Assinatura{} = assinatura), do:

    Email.enviar_email_assinatura_ativa(assinatura) end alterar assinatura da função
  119. defmodule Relatorio do # ... def extrato_por_intervalo(intervalo) do # ...

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

    fim }) do # ... end end extrato_por_intervalo/1 pattern matching
  121. defmodule Usuario do def criar_usuario(%Usuario{} = usuario) do # ...

    end end novo_usuario = %Usuario{ nome: "Elaine", email: "[email protected]", senha: "123", apelido: "elainenaomi", status: 1, ativo: true, admin: false } Usuario.criar_usuario(novo_usuario)
  122. 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}
  123. 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}
  124. 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
  125. 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)
  126. 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
  127. 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}
  128. 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
  129. 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
  130. 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
  131. 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
  132. 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
  133. 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
  134. 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
  135. 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
  136. 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
  137. 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
  138. 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
  139. 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
  140. 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
  141. 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
  142. 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
  143. 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
  144. 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
  145. 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
  146. defmodule Conta do # ... end defmodule Login do #

    ... end defmodule Assinatura do # ... end melhor isolamento dos domínios e regras de negócio
  147. defmodule PessoaFisica do def formatar_documento(%{cpf: cpf}) do # ... end

    end defmodule PessoaJuridica do def formatar_documento(%{cnpj: cnpj}) do # ... end end
  148. 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
  149. 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
  150. 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
  151. 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
  152. 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
  153. 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
  154. 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
  155. 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
  156. 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
  157. 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
  158. 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
  159. 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)
  160. 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)
  161. 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)
  162. 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
  163. 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
  164. 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
  165. 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
  166. 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
  167. 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
  168. apontam possíveis problemas de design alertam sobre redução da qualidade

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

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

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

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

    indicam possível impacto no negócio CODE SMELLS
  173. 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
  174. 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