A Sip of Elixir

A Sip of Elixir

During his career Sascha dabbled with a lot of things: over "classic" Java development, to crafting mobile and responsive web apps, over to building large scalable and resilient backend systems. For the past two years Elixir has been his language of choice for building aforementioned backend systems.

This talk aims to provide a glimpse into how Elixir came to be, what problems it tries to solve and how it solves them. Using concrete examples it will introduce the basic syntactic building blocks of the language and higher-level patterns defining applications built with Elixir.

After all this you should have a basic understanding on what makes Elixir tick and why it's a pleasure to use.

9095331a47468a6898495b05c49ee422?s=128

Sascha Wolf

October 01, 2019
Tweet

Transcript

  1. ilAiSIPlll. OF Elixir Sascha Wolf | ! wolf4earth | saschawolf.me

  2. Sascha Wolf | ! wolf4earth | saschawolf.me

  3. AGENDA ▸ The History of Elixir ▸ Syntax Crash Course

    ▸ Design Aspects Sascha Wolf | ! wolf4earth | saschawolf.me
  4. WHAT IS ELIXIR? Sascha Wolf | ! wolf4earth | saschawolf.me

  5. WHAT IS ELIXIR? Elixir is a dynamic, functional language designed

    for building scalable and maintainable applications. — elixir-lang.org Sascha Wolf | ! wolf4earth | saschawolf.me
  6. TO UNDERSTAND ELIXIR1 WE NEED TO UNDERSTAND ITS HISTORY 1

    and the problems it tries to solve Sascha Wolf | ! wolf4earth | saschawolf.me
  7. THE YEAR IS 2012 Sascha Wolf | ! wolf4earth |

    saschawolf.me
  8. JOSÉ VALIM Sascha Wolf | ! wolf4earth | saschawolf.me

  9. JOSÉ VALIM A well-known Rubyist ▸ Rails 44.2k ⭐ (Contributor)

    ▸ Devise 20.2k ▸ Simple Form 7.5k ▸ And more ... Sascha Wolf | ! wolf4earth | saschawolf.me
  10. CONCURRENCY Sascha Wolf | ! wolf4earth | saschawolf.me

  11. Sascha Wolf | ! wolf4earth | saschawolf.me

  12. ERLANG Sascha Wolf | ! wolf4earth | saschawolf.me

  13. BEAM ERLANG VM Sascha Wolf | ! wolf4earth | saschawolf.me

  14. ACTOR MODEL2 2 Technically almost-actor (https://www.youtube.com/watch?v=_0m0_qtfzLs) Sascha Wolf | !

    wolf4earth | saschawolf.me
  15. source: https://www.brianstorti.com/the-actor-model/

  16. ERLANG WAS CREATED AT ERICSSON FOR TELEPHONY SWITCHES Sascha Wolf

    | ! wolf4earth | saschawolf.me
  17. ▸ Distributed ▸ Fault-tolerant ▸ Soft real-time ▸ High-availability Sascha

    Wolf | ! wolf4earth | saschawolf.me
  18. WORK ON ERLANG STARTED IN 1987 Sascha Wolf | !

    wolf4earth | saschawolf.me
  19. IT WENT OPEN-SOURCE IN 1998 Sascha Wolf | ! wolf4earth

    | saschawolf.me
  20. BATTLE-TESTED IN OVER 30 YEARS OF USAGE Sascha Wolf |

    ! wolf4earth | saschawolf.me
  21. -module(greetings). -export([hello/1]). hello(Name) -> io:format("Hello ~s~n", [Name]). Sascha Wolf |

    ! wolf4earth | saschawolf.me
  22.  RUBY         ERLANG Sascha Wolf | ! wolf4earth | saschawolf.me

  23. Sascha Wolf | ! wolf4earth | saschawolf.me

  24. BEAM Sascha Wolf | ! wolf4earth | saschawolf.me

  25. -module(greetings). -export([hello/1]). hello(Name) -> io:format("Hello ~s~n", [Name]). Sascha Wolf |

    ! wolf4earth | saschawolf.me
  26. defmodule Greetings do def hello(name) do IO.puts("Hello #{name}") end end

    Sascha Wolf | ! wolf4earth | saschawolf.me
  27. RUBY + ERLANG = Elixir Sascha Wolf | ! wolf4earth

    | saschawolf.me
  28. SYNTAX CRASH COURSE Sascha Wolf | ! wolf4earth | saschawolf.me

  29. SYNTAX CRASH COURSE - BASIC TYPES ▸ List: [3, 1,

    4, 1, 5] ▸ Map: %{key: "value"} ▸ Atom: :an_atom ▸ Boolean: true || false ▸ Tuple: {"have some PI", 3.1415, :the_pi_is_a_lie} ▸ Function: fn x, y -> x * y end Sascha Wolf | ! wolf4earth | saschawolf.me
  30. SYNTAX CRASH COURSE - OPERATORS ▸ Basics: +, -, *,

    /, ==, <, >, &&, || ▸ String Concatination: "Hello" <> " Lambda Cologne" ▸ List Concatination: [3, 1, 4] ++ [1, 5] ▸ Pipe: [3, 1, 4, 1, 5] |> Enum.map(fn x -> x * 2 end) |> Enum.sum() Sascha Wolf | ! wolf4earth | saschawolf.me
  31. SYNTAX CRASH COURSE - PIPE iex> [3, 1, 4, 1,

    5] |> Enum.map(fn x -> x * 2 end) |> Enum.sum() 28 iex> Enum.sum(Enum.map([3, 1, 4, 1, 5], fn x -> x * 2 end)) 28 Sascha Wolf | ! wolf4earth | saschawolf.me
  32. Elixir ▸ developer happiness ▸ pattern-matching ▸ syntactic macro system

    ▸ Erlang goodness Sascha Wolf | ! wolf4earth | saschawolf.me
  33. DEVELOPER HAPPINESS Sascha Wolf | ! wolf4earth | saschawolf.me

  34. GREAT TOOLING ▸ build tool mix ▸ code formatter ▸

    unit testing framework ▸ first-class documentation ▸ and more ... Sascha Wolf | ! wolf4earth | saschawolf.me
  35. UNIT TESTING FRAMEWORK ExUnit Sascha Wolf | ! wolf4earth |

    saschawolf.me
  36. defmodule GreetingsTest do use ExUnit.Case, async: true test "it greets

    friendly" do assert Greetings.hello("Lambda Cologne") == "Hello Lambda Cologne!" end end Sascha Wolf | ! wolf4earth | saschawolf.me
  37. Sascha Wolf | ! wolf4earth | saschawolf.me

  38. FIRST-CLASS DOCUMENTATION Sascha Wolf | ! wolf4earth | saschawolf.me

  39. None
  40. defmodule Greetings do @doc """ Prints a friendly greeting. ##

    Examples iex> Greetings.hello("Lambda Cologne") "Hello Lambda Cologne!" """ def hello(name) do IO.puts("Hello #{name}") end end Sascha Wolf | ! wolf4earth | saschawolf.me
  41. Sascha Wolf | ! wolf4earth | saschawolf.me

  42. None
  43. defmodule GreetingsTest do use ExUnit.Case, async: true doctest Greetings end

    Sascha Wolf | ! wolf4earth | saschawolf.me
  44. Sascha Wolf | ! wolf4earth | saschawolf.me

  45. AND MORE ... ▸ Powerful interactive console (iex) ▸ "Batteries

    included" web framework (Phoenix) ▸ A bunch more neat Erlang/OTP things: ▸ Supervision trees, observer, remote debugging, hot code upgrades ... Sascha Wolf | ! wolf4earth | saschawolf.me
  46. PATTERN MATCHING Sascha Wolf | ! wolf4earth | saschawolf.me

  47. iex> my_list = [3, 1, 4, 1, 5, 9, 2,

    6, 5] iex> [first, second | rest] = my_list iex> first 3 iex> second 1 iex> rest [4, 1, 5, 9, 2, 6, 5] Sascha Wolf | ! wolf4earth | saschawolf.me
  48. iex> my_map = %{a: 1, b: 2, c: 3} iex>

    %{a: a, b: b} = my_map iex> a 1 iex> b 2 Sascha Wolf | ! wolf4earth | saschawolf.me
  49. iex> greeting = "Hello Lambda Cologne" iex> "Hello " <>

    name = greeting iex> name "Lambda Cologne" Sascha Wolf | ! wolf4earth | saschawolf.me
  50. = IS THE ASSIGNMENT OPERATOR MATCH OPERATOR Sascha Wolf |

    ! wolf4earth | saschawolf.me
  51. iex> "Hello " <> name = "Salut Lambda Cologne" **

    (MatchError) no match of right hand side value: "Salut Lambda Cologne" (stdlib) erl_eval.erl:453: :erl_eval.expr/5 (iex) lib/iex/evaluator.ex:257: IEx.Evaluator.handle_eval/5 (iex) lib/iex/evaluator.ex:237: IEx.Evaluator.do_eval/3 (iex) lib/iex/evaluator.ex:215: IEx.Evaluator.eval/3 (iex) lib/iex/evaluator.ex:103: IEx.Evaluator.loop/1 (iex) lib/iex/evaluator.ex:27: IEx.Evaluator.init/4 Sascha Wolf | ! wolf4earth | saschawolf.me
  52. PATTERN MATCHING IS EVERYWHERE Sascha Wolf | ! wolf4earth |

    saschawolf.me
  53. defmodule Greetings do def hello("") do hello("anonymous") end def hello("Lambda

    " <> city) do hello("FP-Enthusiast from #{city}") end def hello(name) do "Hello #{name}!" end end Sascha Wolf | ! wolf4earth | saschawolf.me
  54. SYNTACTIC MACROS Sascha Wolf | ! wolf4earth | saschawolf.me

  55. TRANSFORM THE AST ABSTRACT SYNTAX TREE Sascha Wolf | !

    wolf4earth | saschawolf.me
  56. USE THE FULL POWER OF Elixir Sascha Wolf | !

    wolf4earth | saschawolf.me
  57. defmodule Conditional do defmacro if(condition, do: true_block, else: false_block) do

    quote do case unquote(condition) do true -> unquote(true_block) false -> unquote(false_block) end end end end Sascha Wolf | ! wolf4earth | saschawolf.me
  58. iex> import Conditional iex> if true do ...> "dis is

    true" ...> else ...> "dis is false" ...> end "dis is true" Sascha Wolf | ! wolf4earth | saschawolf.me
  59. application/andrew-inset ez application/applixware aw application/atom+xml atom application/atomcat+xml atomcat application/atomsvc+xml atomsvc

    application/ccxml+xml ccxml application/cdmi-capability cdmia application/cdmi-container cdmic application/cdmi-domain cdmid application/cdmi-object cdmio application/cdmi-queue cdmiq application/cu-seeme cu Sascha Wolf | ! wolf4earth | saschawolf.me
  60. defmodule MimeType do "path/to/mime-types.txt" |> File.read!() |> Enum.map(fn line ->

    [mime_type, extension] = String.split(line, " ", trim: true) def to_extension(unquote(mime_type)), do: unquote(extension) end) end Sascha Wolf | ! wolf4earth | saschawolf.me
  61. iex> MimeType.to_extension("application/applixware") "aw" Sascha Wolf | ! wolf4earth | saschawolf.me

  62. Elixir MACROS ARE HYGENIC Sascha Wolf | ! wolf4earth |

    saschawolf.me
  63. ERLANG GOODNESS Sascha Wolf | ! wolf4earth | saschawolf.me

  64. -module(greetings). -export([hello/1]). hello(Name) -> io:format("Hello ~s~n", [Name]). Sascha Wolf |

    ! wolf4earth | saschawolf.me
  65. defmodule Greetings do def hello(name) do :greetings.hello(name) end end Sascha

    Wolf | ! wolf4earth | saschawolf.me
  66. OTP OPEN TELECOM PLATFORM Sascha Wolf | ! wolf4earth |

    saschawolf.me
  67. OPEN TELECOM PLATFORM If half of Erlang's greatness comes from

    its concurrency and distribution and the other half comes from its error handling capabilities, then the OTP framework is the third half of it. — Learn You Some Erlang for Great Good! (Frederic Trottier-Hebert)3 3 https://learnyousomeerlang.com/what-is-otp Sascha Wolf | ! wolf4earth | saschawolf.me
  68. PROCESS ACTOR Sascha Wolf | ! wolf4earth | saschawolf.me

  69. DATABASE CONNECTION Sascha Wolf | ! wolf4earth | saschawolf.me

  70. DATABASE CONNECTION ▸ establish a connection ▸ do some work*

    ▸ disconnect Sascha Wolf | ! wolf4earth | saschawolf.me
  71. DATABASE CONNECTION ▸ establish a connection ▸ run a query*

    ▸ disconnect * Usually you would have some kind of checkout/checkin mechanism Sascha Wolf | ! wolf4earth | saschawolf.me
  72. GENSERVER Sascha Wolf | ! wolf4earth | saschawolf.me

  73. defmodule DbConnection do use GenServer def init(uri) do connection =

    MyDatabase.establish_connection(uri) {:ok, connection} end def handle_call({:query, query}, _from, connection) do result = MyDatabase.run_query(connection, query) {:reply, result, connection} end def handle_cast(:disconnect, connection) do connection = MyDatabase.close_connection(connection) {:stop, :normal, connection} end end Sascha Wolf | ! wolf4earth | saschawolf.me
  74. iex> {:ok, pid} = GenServer.start_link(DbConnection, "my-database-uri") iex> query = "SELECT

    * FROM users" iex> GenServer.call(pid, {:query, query}) [ ... ] # List of users iex> GenServer.cast(pid, :disconnect) :ok Sascha Wolf | ! wolf4earth | saschawolf.me
  75. defmodule DbConnection do use GenServer def start_link(uri) do GenServer.start_link(DbConnection, uri)

    end def query(pid, query) do GenServer.call(pid, {:query, query}) end def disconnect(pid) do GenServer.cast(pid, :disconnect) end # init, handle_call, handle_cast end Sascha Wolf | ! wolf4earth | saschawolf.me
  76. WHAT IF THE DATABASE GOES DOWN? Sascha Wolf | !

    wolf4earth | saschawolf.me
  77. ! Sascha Wolf | ! wolf4earth | saschawolf.me

  78. Let it crash — Old Erlang wisdom Sascha Wolf |

    ! wolf4earth | saschawolf.me
  79. Let it crash 131 out of 132 bugs are transient

    bugs — Erlang in Anger (which refers here to Jim Gray)4 4 https://www.erlang-in-anger.com Sascha Wolf | ! wolf4earth | saschawolf.me
  80. EXAMPLES OF TRANSIENT BUGS ▸ Network request fails ▸ File

    IO has a hickup ▸ Odd race condition ▸ Weird datetime issue ▸ Database goes down Sascha Wolf | ! wolf4earth | saschawolf.me
  81. Let it crash — Old Erlang wisdom Sascha Wolf |

    ! wolf4earth | saschawolf.me
  82. SUPERVISORS Sascha Wolf | ! wolf4earth | saschawolf.me

  83. SUPERVISORS The supervisor is responsible for starting, stopping, and monitoring

    its child processes. The basic idea of a supervisor is that it must keep its child processes alive by restarting them when necessary. — Erlang Documentation5 5 http://erlang.org/doc/man/supervisor.html#supervision-principles Sascha Wolf | ! wolf4earth | saschawolf.me
  84. None
  85. defmodule MyApp.Application do # See https://hexdocs.pm/elixir/Application.html # for more information

    on OTP Applications use Application def start(_type, _args) do # List all child processes to be supervised children = [ MyApp.Repo, MyApp.Endpoint ] # See https://hexdocs.pm/elixir/Supervisor.html # for other strategies and supported options opts = [strategy: :one_for_one, name: MyApp.Supervisor] Supervisor.start_link(children, opts) end end Sascha Wolf | ! wolf4earth | saschawolf.me
  86. STANDING ON THE SHOULDERS OF GIANTS ▸ Agent - keep

    and manipulate state ▸ Task - easy asynchronous processing ▸ GenStage - exchange events with back-pressure between producer and consumer processes Sascha Wolf | ! wolf4earth | saschawolf.me
  87. THERE'S MORE ... ▸ remote debugging ▸ built-in support for

    node clustering ▸ hot code upgrades (upgrade while running) ▸ great support for metrics and introspection ▸ ... Sascha Wolf | ! wolf4earth | saschawolf.me
  88. SUMMARY Sascha Wolf | ! wolf4earth | saschawolf.me

  89. Elixir ▸ functional and dynamically typed ▸ focusses on developer

    happiness ▸ considers documentation a first-class citizen ▸ provides a full syntactic macro system ▸ stands on the shoulders of giants (Erlang/OTP) Sascha Wolf | ! wolf4earth | saschawolf.me
  90. THANK YOU FOR LISTENING Sascha Wolf | ! wolf4earth |

    saschawolf.me
  91. QUESTIONS? Sascha Wolf | ! wolf4earth | saschawolf.me