$30 off During Our Annual Pro Sale. View details »

From Ruby to Elixir

From Ruby to Elixir

my talk at Sardines.rb (Lisbon Ruby meetup)

Daniel Serrano

August 13, 2019
Tweet

More Decks by Daniel Serrano

Other Decks in Programming

Transcript

  1. from Ruby to Elixir

  2. • why elixir? • historical context • quick intro •

    pipe operator • pattern-matching • processes • supervisors • phoenix • elixir in real life outline
  3. • elixir • preemptive Erlang VM • yielding lightweight processes

    • no locks, no mutexes, etc. • ranch, cowboy • functional, immutable • ruby • MRI relies on GIL • OS processes, threads • locks, mutexes, etc. • WEBrick, unicorn, puma, passenger, etc. • OO, mutable why elixir?
  4. historical context • Erlang (1986) • Ericsson (OSS 1998) •

    Ruby (1995) • Rails (2005) • F# (2005) • Clojure (2007) • Devise (2009) • Elixir (2009)
  5. quick intro • integers • 2, 0xcafe, 0b100, 10_000 •

    floats • 1.0, 3.1415, 6.02e23 • lists • [1, 2, 3], [head|tail] • map • %{one: “un”, two: “deux”} • atom • :foo, :me@home, :elixir • tuple • {:ok, 11, ‘hi'} • keyword list • [a: :foo, b: :bar] • binary • <<104, 101, 108, 108, 111>>, “hello”
  6. quick intro • functions • Enum.map/2, :erlang.localtime/0 • examples •

    IO.puts(“Hello World”) • Map.get(%{one: “un”}, :one) • struct(User, %{fname: “John”, lname: “Doe”}) # prints to stdout # returns “un” # returns a User struct # with first name “John”, # last name “Doe”
  7. quick intro defmodule User do defstruct [:fname, :lname] def full_name(%User{fname:

    fname, lame: lname}) do “#{fname} #{lname}” end end $> user = %User{fname: “John”, lname: “Doe”} $> User.full_name(user) “John Doe”
  8. pipe operator |> Enum.max(Enum.map(Enum.filter([1, 2, 3, 4, 5], fn x

    -> rem(x, 2) == 0 end), fn x-> x * 2 end)) • find max of double the values
  9. pipe operator |> Enum.max( Enum.map( Enum.filter( [1, 2, 3, 4,

    5], fn x -> rem(x, 2) == 0 end ), fn x-> x * 2 end ) )
  10. pipe operator |> [1, 2, 3, 4, 5] |> Enum.filter(fn

    x -> rem(x, 2) == 0 end) |> Enum.map(fn x -> x * 2 end) |> Enum.max() # 8
  11. pattern-matching def zero?(0), do: true def zero?(_), do: false zero?(0)

    zero?(3) zero?(“hello”) # true # false # false
  12. pattern-matching def started_at_text(%Task{started_at: nil}), do: “Not started” def started_at_text(%Task{started_at: time}

    = task) do
 “Started task-#{task.id} @ #{DateTime.to_string(time)}” end def state(%Task{started_at: nil, closed_at: nil}), do: :waiting def state(%Task{started_at: nil}), do: :canceled def state(%Task{closed_at: nil}), do: :in_progress
  13. processes process A process B

  14. processes BEAM

  15. processes BEAM 2000 reductions each before yielding multiple schedulers ~1

    per cpu
  16. processes BEAM

  17. processes BEAM

  18. processes BEAM eu-west-1 us-east-1

  19. supervisors BEAM

  20. supervisors BEAM error

  21. supervisors BEAM restart

  22. one_for_one restart supervisors BEAM

  23. one_for_all restart supervisors BEAM

  24. phoenix

  25. phoenix

  26. phoenix Ruby Elixir Rack Plug Rails Phoenix ActiveRecord Ecto ERB

    EEx
  27. elixir in real life • 1.5 billion page views per

    month • 200.000 concurrent users • resource intensive features • previously aggressive horizontal scaling • now 1/10th servers with low CPU usage
  28. elixir in real life • 100.000 concurrent users • previously

    Java • now Erlang, Go and Elixir • 10.000s to 100.000s users per machine
  29. elixir in real life • 11.000.000 concurrent users • 2.600.000

    concurrent voice users • 220 Gbps • 120 Mpps
  30. elixir in real life • media service handling millions of

    reqs/day • biometrics aggregator service handling 100.000s connections per day • average of 6 Kubernetes pods • cpu limits of 600m • mem limits of 512Mi
  31. the end thank you dnlserrano.dev