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

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

Tobias Pfeiffer

March 08, 2018
Tweet

More Decks by Tobias Pfeiffer

Other Decks in Programming

Transcript

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

    View Slide

  2. View Slide

  3. View Slide

  4. View Slide

  5. Can't go out and
    rewrite it all

    View Slide

  6. You shouldn’t

    View Slide

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

    View Slide

  8. Your Monolith and You

    View Slide

  9. View Slide

  10. Your Monolith now?

    View Slide

  11. Your Monolith?

    View Slide

  12. Tear it all down and
    rewrite it

    View Slide

  13. View Slide

  14. Sooooon!

    View Slide

  15. “We rewrote it all in
    Language x, now it’s 10
    times faster and only
    50% of the code!”
    Someone

    View Slide

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

    View Slide

  17. What nobody tells you...

    View Slide

  18. Business Value?

    View Slide

  19. Sooooon!

    View Slide

  20. Replace it step by step

    View Slide

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

    View Slide

  22. Terraform allows you to
    incrementally transform an
    older API into one powered by
    Phoenix - one endpoint at a
    time.
    poteto/terraform

    View Slide

  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

    View Slide

  24. Replace a critical
    component

    View Slide

  25. Check out our sweet new
    heating system!

    View Slide

  26. Write a new component

    View Slide

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

    View Slide

  28. Write a new component
    Obvious in microservices

    View Slide

  29. “Is the technology I’m
    choosing the right fit for
    the problem I’m trying to
    solve?”
    Everyone, hopefully

    View Slide

  30. Reasonably separate and
    limited problem

    View Slide

  31. Requirement that poses a
    problem for the current
    stack

    View Slide

  32. Spark of Enthusiasm

    View Slide

  33. Courier Tracking

    View Slide

  34. Courier Tracking

    View Slide

  35. Courier Tracking

    View Slide

  36. Courier Tracking
    Websockets

    View Slide

  37. Courier Tracking
    Websockets
    Basic Knowledge

    View Slide

  38. How to make them talk?

    View Slide

  39. Monolith
    Frontend
    Courier
    DB

    View Slide

  40. Monolith
    Tracking
    Frontend
    Courier
    DB DB

    View Slide

  41. Connect them?

    View Slide

  42. Monolith
    Tracking
    Frontend
    Courier
    DB DB

    View Slide

  43. JSON
    Web
    Token

    View Slide

  44. Header
    Payload
    Signature

    View Slide

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

    View Slide

  46. Monolith
    Tracking
    Frontend
    Courier
    DB DB
    Shared Secret

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  51. def join("courier:" <> courier_id, _, %
    {assigns: %{user: user}}) do
    if authorized?(courier_id, user) do
    # login
    else
    # unauthorizd
    end
    end
    Channel

    View Slide

  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

    View Slide

  53. Monolith
    Tracking
    Frontend
    Courier
    DB DB
    Locations
    Locations
    Most of the time

    View Slide

  54. Fulfillment

    View Slide

  55. Fulfillment
    CRUD

    View Slide

  56. Fulfillment
    CRUD
    Experience

    View Slide

  57. Monolith
    Fulfillment
    DB DB

    View Slide

  58. Monolith
    Fulfillment
    DB DB
    Own UI

    View Slide

  59. Monolith
    Fulfillment
    DB DB
    OAuth
    OAuth

    View Slide

  60. Monolith
    Fulfillment
    DB DB
    /current_user
    Who?

    View Slide

  61. Monolith
    Fulfillment
    DB DB
    Products

    View Slide

  62. Monolith
    Fulfillment
    DB DB
    Order
    Valid?
    Order

    View Slide

  63. Monolith
    Fulfillment
    DB DB
    Packaging
    Create

    View Slide

  64. Rail-way oriented
    programming!

    View Slide

  65. Railway Oriented Programming

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  72. No Kafka/Message Queue?

    View Slide

  73. Be careful with new
    technologies!

    View Slide

  74. Microservices!

    View Slide

  75. Microservices!
    ”Macroapplications”

    View Slide

  76. All challenges are
    clearly technical

    View Slide

  77. All challenges are
    clearly technical

    View Slide

  78. Stakeholders

    View Slide

  79. Your team

    View Slide

  80. First Major Version

    View Slide

  81. Get the others on board

    View Slide

  82. Workshops

    View Slide

  83. To know it,
    you got to build it

    View Slide

  84. View Slide

  85. Pair Adopter with Alchemist

    View Slide

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

    View Slide

  87. Knowledge

    View Slide

  88. Knowledge

    View Slide

  89. “We are still using this
    like Rails – we should
    use GenServers!”
    Someone on your team

    View Slide

  90. You don’t need to kill
    your Monolith,
    Complement it

    View Slide

  91. Your Apps

    View Slide

  92. Enjoy using Elixir effectively to help
    your company
    Tobias Pfeiffer
    @PragTob
    pragtob.info

    View Slide