Elixir, your Monolith and You

Elixir, your Monolith and You

Elixir is great, so clearly we'll all rewrite our applications in Elixir. Mostly, you can't and shouldn't do that. This presentation will show you another path. You’ll see how at Liefery, we started with small steps instead of rewriting everything. This allowed us to reap the benefits earlier and get comfortable before getting deeper into it. We’ll examine in detail the tactics we used to create two Elixir apps for new requirements, and how we integrated them with our existing Rails code base.

Join us on our tale of adopting Elixir and Phoenix and see what we learned, what we loved, and what bumps we hit along the road

8480daec7137f28565bc2d2e666b915a?s=128

Tobias Pfeiffer

March 08, 2018
Tweet

Transcript

  1. Who wants to go and build a system in Elixir?

  2. None
  3. None
  4. None
  5. Can't go out and rewrite it all

  6. You shouldn’t

  7. Elixir, your Monolith and You (alpha-1) Tobias Pfeiffer @PragTob pragtob.info

  8. Your Monolith and You

  9. None
  10. Your Monolith now?

  11. Your Monolith?

  12. Tear it all down and rewrite it

  13. None
  14. Sooooon!

  15. “We rewrote it all in Language x, now it’s 10

    times faster and only 50% of the code!” Someone
  16. “Language x, is 10 times faster and requires 50% of

    the code of language Y!” Someone Often implies...
  17. What nobody tells you...

  18. Business Value?

  19. Sooooon!

  20. Replace it step by step

  21. We have a bedroom, for the bathroom please check out

    legacy!
  22. Terraform allows you to incrementally transform an older API into

    one powered by Phoenix - one endpoint at a time. poteto/terraform
  23. defmodule MyApp.Terraformers.Foo do alias MyApp.Clients.Foo use Plug.Router plug :match plug

    :dispatch get "/v1/hello-world", do: send_resp(conn, 200, "Hi") get _ do res = Foo.get!(conn) send_response({:ok, conn, res}) end end poteto/terraform
  24. Replace a critical component

  25. Check out our sweet new heating system!

  26. Write a new component

  27. Check it out we built a brand new high tech

    entertainment facility!
  28. Write a new component Obvious in microservices

  29. “Is the technology I’m choosing the right fit for the

    problem I’m trying to solve?” Everyone, hopefully
  30. Reasonably separate and limited problem

  31. Requirement that poses a problem for the current stack

  32. Spark of Enthusiasm

  33. Courier Tracking

  34. Courier Tracking

  35. Courier Tracking

  36. Courier Tracking Websockets

  37. Courier Tracking Websockets Basic Knowledge

  38. How to make them talk?

  39. Monolith Frontend Courier DB

  40. Monolith Tracking Frontend Courier DB DB

  41. Connect them?

  42. Monolith Tracking Frontend Courier DB DB

  43. JSON Web Token

  44. Header Payload Signature

  45. { "role": "admin", "courier_ids": [1337, 55], "id": 42, "exp": 1520469475

    }
  46. Monolith Tracking Frontend Courier DB DB Shared Secret

  47. Monolith Tracking Frontend Courier DB DB JWT JWT Shared Secret

  48. Monolith Tracking Frontend Courier DB DB JWT JWT JWT Shared

    Secret JWT
  49. def connect(%{"token" => token}, socket) do token |> JWT.verify_token |>

    respond_based_on_token_contents(socket) end Socket
  50. defp login_user(%{"role" => role, ...}, socket) do {:ok, assign(socket, :user,

    %{role: role, ...})} end Socket
  51. def join("courier:" <> courier_id, _, % {assigns: %{user: user}}) do

    if authorized?(courier_id, user) do # login else # unauthorizd end end Channel
  52. defp authorized?("", _), do: false defp authorized?(courier_id, %{courier_ids: ids}) do

    Enum.member?(ids, String.to_integer(courier_id)) end defp authorized?(_, _), do: false Channel
  53. Monolith Tracking Frontend Courier DB DB Locations Locations Most of

    the time
  54. Fulfillment

  55. Fulfillment CRUD

  56. Fulfillment CRUD Experience

  57. Monolith Fulfillment DB DB

  58. Monolith Fulfillment DB DB Own UI

  59. Monolith Fulfillment DB DB OAuth OAuth

  60. Monolith Fulfillment DB DB /current_user Who?

  61. Monolith Fulfillment DB DB Products

  62. Monolith Fulfillment DB DB Order Valid? Order

  63. Monolith Fulfillment DB DB Packaging Create

  64. Rail-way oriented programming!

  65. Railway Oriented Programming

  66. defmodule Fulfillment.OrderCreation do def create(params, customer, auth) do with {:ok,

    order} <- validate_order(params, customer), {:ok, order} <- validate_in_backend(order, auth), {:ok, order} <- Repo.insert(order) do {:ok, order} else {:error, changeset} -> {:error, changeset} end end end
  67. defmodule Fulfillment.OrderCreation do def create(params, customer, auth) do with {:ok,

    order} <- validate_order(params, customer), {:ok, order} <- validate_in_backend(order, auth), {:ok, order} <- Repo.insert(order) do {:ok, order} else {:error, changeset} -> {:error, changeset} end end end Validate internally
  68. defmodule Fulfillment.OrderCreation do def create(params, customer, auth) do with {:ok,

    order} <- validate_order(params, customer), {:ok, order} <- validate_in_backend(order, auth), {:ok, order} <- Repo.insert(order) do {:ok, order} else {:error, changeset} -> {:error, changeset} end end end Validate externally
  69. defmodule Fulfillment.OrderCreation do def create(params, customer, auth) do with {:ok,

    order} <- validate_order(params, customer), {:ok, order} <- validate_in_backend(order, auth), {:ok, order} <- Repo.insert(order) do {:ok, order} else {:error, changeset} -> {:error, changeset} end end end Save
  70. defmodule Fulfillment.OrderCreation do def create(params, customer, auth) do with {:ok,

    order} <- validate_order(params, customer), {:ok, order} <- validate_in_backend(order, auth), {:ok, order} <- Repo.insert(order) do {:ok, order} else {:error, changeset} -> {:error, changeset} end end end Done
  71. defmodule Fulfillment.OrderCreation do def create(params, customer, auth) do with {:ok,

    order} <- validate_order(params, customer), {:ok, order} <- validate_in_backend(order, auth), {:ok, order} <- Repo.insert(order) do {:ok, order} else {:error, changeset} -> {:error, changeset} end end end Error
  72. No Kafka/Message Queue?

  73. Be careful with new technologies!

  74. Microservices!

  75. Microservices! ”Macroapplications”

  76. All challenges are clearly technical

  77. All challenges are clearly technical

  78. Stakeholders

  79. Your team

  80. First Major Version

  81. Get the others on board

  82. Workshops

  83. To know it, you got to build it

  84. None
  85. Pair Adopter with Alchemist

  86. Pair Adopter with Alchemist Alchemist doesn’t touch keyboard

  87. Knowledge

  88. Knowledge

  89. “We are still using this like Rails – we should

    use GenServers!” Someone on your team
  90. You don’t need to kill your Monolith, Complement it

  91. Your Apps

  92. Enjoy using Elixir effectively to help your company Tobias Pfeiffer

    @PragTob pragtob.info