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

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.

Sascha Wolf

October 01, 2019
Tweet

More Decks by Sascha Wolf

Other Decks in Programming

Transcript

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

    ▸ Design Aspects Sascha Wolf | ! wolf4earth | saschawolf.me
  2. WHAT IS ELIXIR? Elixir is a dynamic, functional language designed

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

    and the problems it tries to solve Sascha Wolf | ! wolf4earth | saschawolf.me
  4. JOSÉ VALIM A well-known Rubyist ▸ Rails 44.2k ⭐ (Contributor)

    ▸ Devise 20.2k ▸ Simple Form 7.5k ▸ And more ... Sascha Wolf | ! wolf4earth | saschawolf.me
  5. 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
  6. 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
  7. 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
  8. Elixir ▸ developer happiness ▸ pattern-matching ▸ syntactic macro system

    ▸ Erlang goodness Sascha Wolf | ! wolf4earth | saschawolf.me
  9. GREAT TOOLING ▸ build tool mix ▸ code formatter ▸

    unit testing framework ▸ first-class documentation ▸ and more ... Sascha Wolf | ! wolf4earth | saschawolf.me
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. iex> greeting = "Hello Lambda Cologne" iex> "Hello " <>

    name = greeting iex> name "Lambda Cologne" Sascha Wolf | ! wolf4earth | saschawolf.me
  16. 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
  17. 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
  18. 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
  19. iex> import Conditional iex> if true do ...> "dis is

    true" ...> else ...> "dis is false" ...> end "dis is true" Sascha Wolf | ! wolf4earth | saschawolf.me
  20. 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
  21. 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
  22. 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
  23. DATABASE CONNECTION ▸ establish a connection ▸ do some work*

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

    ▸ disconnect * Usually you would have some kind of checkout/checkin mechanism Sascha Wolf | ! wolf4earth | saschawolf.me
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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
  31. 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
  32. 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
  33. 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
  34. 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