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

Elixir Elevated: the Ups and Downs of OTP

Elixir Elevated: the Ups and Downs of OTP

Given July, 25, 2014 at ElixirConf #1
Using an elevator bank simulator as an overview of the concepts behind OTP. Example code available: https://github.com/gvaughn/elixir_elevated/tree/elixirconf2014

Greg Vaughn

July 25, 2014
Tweet

More Decks by Greg Vaughn

Other Decks in Programming

Transcript

  1. Elixir Elevated! The Ups and Downs of OTP Greg V

    aughn! [email protected]! twitter: @gregvaughn, github/irc: gvaughn
  2. Student of Elixir and OTP! Hobbying with Elixir almost 13

    months! Texan! Professional Programmer of 20 years! Across 6 languages! Employed by LivingSocial
  3. Student of Elixir and OTP! Hobbying with Elixir almost 13

    months! Texan! Professional Programmer of 20 years! Across 6 languages! Employed by LivingSocial LivingSocial is Hiring!
  4. OTP is … Mature / Battle Tested for 16 (18?)

    years Microservices Object Oriented (NOT class oriented)
  5. OTP is … Mature / Battle Tested for 16 (18?)

    years Microservices Object Oriented (NOT class oriented) Actor
  6. OTP is … Mature / Battle Tested for 16 (18?)

    years Microservices Object Oriented (NOT class oriented) Actor Framework (Hollywood Principle)
  7. OTP is … Mature / Battle Tested for 16 (18?)

    years Microservices Object Oriented (NOT class oriented) Actor Framework (Hollywood Principle) Design Patterns
  8. OTP is … Mature / Battle Tested for 16 (18?)

    years Microservices Object Oriented (NOT class oriented) Actor Framework (Hollywood Principle) Design Patterns Robust
  9. object oriented OOP to me means only messaging, local retention

    and protection and ! hiding of state-process, and extreme late-binding of all things. — Alan Kay
  10. object oriented OOP to me means only messaging, local retention

    and protection and ! hiding of state-process, and extreme late-binding of all things. — Alan Kay functional a style of building the structure and elements of computer programs that treats computation as the evaluation of mathematical functions and avoids state and mutable data. — Wikipedia
  11. object oriented OOP to me means only messaging, local retention

    and protection and ! hiding of state-process, and extreme late-binding of all things. — Alan Kay functional a style of building the structure and elements of computer programs that treats computation as the evaluation of mathematical functions and avoids state and mutable data. — Wikipedia concurrent The conceptually simultaneous execution of more than one sequential program on a computer or network of computers. — McGraw-Hill Sci & Tech Dictionary
  12. Behaviours: Don’t call us, we’ll call you defmodule MyCallback do

    use GenServer end iex> {:ok, pid} = GenServer.start(MyCallback, [])
  13. Behaviours: Don’t call us, we’ll call you defmodule MyCallback do

    use GenServer end iex> {:ok, pid} = GenServer.start(MyCallback, []) defmodule GenServer do defmacro __using__(_) do quote do @behaviour :gen_server ! def init(args), do: {:ok, args} ! def handle_cast(msg, state), do: {:stop, {:bad_cast, msg}, state} ! def handle_call(msg, _from, state), do: {:stop, {:bad_call, msg}, state} ! def handle_info(_msg, state), do: {:noreply, state} ! def terminate(_reason, _state), do: :ok ! def code_change(_old, state, _extra), do: {:ok, state} ! defoverridable [init: 1, handle_call: 3, handle_info: 2, handle_cast: 2, terminate: 2, code_change: 3] end end … end
  14. defmodule MyCallback do use GenServer @initial_state %{} ! def start_link

    do GenServer.start_link(__MODULE__, @initial_state) end ! def init(arg) do state = arg {:ok, state} end ! def do_it(pid, param) do GenServer.call(pid, {:do_it, param}) end ! def handle_call({:do_it, param}, _from, state) do payload = get_payload(param, state) new_state = update_state(param, state) {:reply, payload, new_state} end ! defp get_payload(param, state), do: “I DONE DID IT!” ! defp update_state(param, state), do: state end
  15. defmodule MyCallback do use GenServer @initial_state %{} ! def start_link

    do GenServer.start_link(__MODULE__, @initial_state) end ! def init(arg) do state = arg {:ok, state} end ! def do_it(pid, param) do GenServer.call(pid, {:do_it, param}) end ! def handle_call({:do_it, param}, _from, state) do payload = get_payload(param, state) new_state = update_state(param, state) {:reply, payload, new_state} end ! defp get_payload(param, state), do: “I DONE DID IT!” ! defp update_state(param, state), do: state end
  16. defmodule MyCallback do use GenServer @initial_state %{} ! def start_link

    do GenServer.start_link(__MODULE__, @initial_state) end ! def init(arg) do state = arg {:ok, state} end ! def do_it(pid, param) do GenServer.call(pid, {:do_it, param}) end ! def handle_call({:do_it, param}, _from, state) do payload = get_payload(param, state) new_state = update_state(param, state) {:reply, payload, new_state} end ! defp get_payload(param, state), do: “I DONE DID IT!” ! defp update_state(param, state), do: state end
  17. defmodule MyCallback do use GenServer @initial_state %{} ! def start_link

    do GenServer.start_link(__MODULE__, @initial_state) end ! def init(arg) do state = arg {:ok, state} end ! def do_it(pid, param) do GenServer.call(pid, {:do_it, param}) end ! def handle_call({:do_it, param}, _from, state) do payload = get_payload(param, state) new_state = update_state(param, state) {:reply, payload, new_state} end ! defp get_payload(param, state), do: “I DONE DID IT!” ! defp update_state(param, state), do: state end
  18. defmodule MyCallback do use GenServer @initial_state %{} ! def start_link

    do GenServer.start_link(__MODULE__, @initial_state) end ! def init(arg) do state = arg {:ok, state} end ! def do_it(pid, param) do GenServer.call(pid, {:do_it, param}) end ! def handle_call({:do_it, param}, _from, state) do payload = get_payload(param, state) new_state = update_state(param, state) {:reply, payload, new_state} end ! defp get_payload(param, state), do: “I DONE DID IT!” ! defp update_state(param, state), do: state end Client Process Server Process
  19. A rider on any floor presses the up or down

    button! An elevator car arrives! Rider enters and presses a destination floor button rider hall! signal hall! signal car car rider floor hail retrieve arrival arrival go to
  20. A rider on any floor presses the up or down

    button! An elevator car arrives! Rider enters and presses a destination floor button rider hall! signal hall! signal car car rider floor hail retrieve arrival arrival go to Hail struct
  21. Let It Fail … and Respond Separation of Concerns! Think

    Long and Hard about Failure Response! BEAM (not OS) Processes! Finer Grained Control
  22. Prepare to Fail Car! Supervisor Car 1 Car n …

    one_for_one Gen! Event Hall! Signal
  23. Prepare to Fail Car! Supervisor Car 1 Car n …

    one_for_one Gen! Event Hall! Signal Bank! Supervisor rest_for_one
  24. Prepare to Fail Gen! Event HS Bank A! Supervisor CS

    Gen! Event HS Bank B! Supervisor CS Elevator! Supervisor one_for_one
  25. Prepare to Fail Gen! Event HS Bank A! Supervisor CS

    Gen! Event HS Bank B! Supervisor CS Elevator! Supervisor one_for_one Gen Event Gen Event
  26. Don’t Trip defmodule MySupervisor do use Supervisor ! def init(…)

    do workers = worker(MyCallback, [p1, p2, [name: :myc]], [id: :mine]) supervise(workers, strategy: one_for_one) end end ! defmodule MyCallback do use GenServer ! def start_link(p1, p2, opts \\ []) GenServer.start_link(__MODULE__, [p1, p2], opts) end ! def init([p1, p2]) do {:ok, %{p1: p1, p2: p2}} end end
  27. Don’t Trip defmodule MySupervisor do use Supervisor ! def init(…)

    do workers = worker(MyCallback, [p1, p2, [name: :myc]], [id: :mine]) supervise(workers, strategy: one_for_one) end end ! defmodule MyCallback do use GenServer ! def start_link(p1, p2, opts \\ []) GenServer.start_link(__MODULE__, [p1, p2], opts) end ! def init([p1, p2]) do {:ok, %{p1: p1, p2: p2}} end end apply: list of params
  28. Don’t Trip defmodule MySupervisor do use Supervisor ! def init(…)

    do workers = worker(MyCallback, [p1, p2, [name: :myc]], [id: :mine]) supervise(workers, strategy: one_for_one) end end ! defmodule MyCallback do use GenServer ! def start_link(p1, p2, opts \\ []) GenServer.start_link(__MODULE__, [p1, p2], opts) end ! def init([p1, p2]) do {:ok, %{p1: p1, p2: p2}} end end apply: list of params single term for init/1
  29. Trip-less Convention? defmodule MySupervisor do use Supervisor ! def init(…)

    do workers = worker(MyCallback, [{p1, p2}, name: :myc], [id: :mine]) supervise(workers, strategy: one_for_one) end end ! defmodule MyCallback do use GenServer ! def start_link(init_params, opts \\ []) GenServer.start_link(__MODULE__, init_params, opts) end ! def init({p1, p2}) do {:ok, %{p1: p1, p2: p2}} end end
  30. Takeaways Behaviours vs. Callback Modules! Watch your initialization steps! Watch

    parameter and return value contracts! Supervisors and Strategies! Config
  31. Thank you Elixir Elevated! The Ups and Downs of OTP!

    ! Greg Vaughn! ! [email protected]! twitter: @gregvaughn! github/irc: gvaughn http://github.com/gvaughn/elixir_elevated/tree/elixirconf2014