SlideShare a Scribd company logo
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
Elixir and Phoenix
fast, concurrent and explicit
Tobias Pfeiffer
@PragTob
pragtob.info
Elixir and Phoenix
fast, concurrent and explicit
Tobias Pfeiffer
@PragTob
pragtob.info
Elixir & Phoenix – fast, concurrent and explicit
Platform
defmodule MyMap do
@doc """
iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
"""
def map(list, function) do
Enum.reverse do_map([], list, function)
end
defp do_map(acc, [], _function) do
acc
end
defp do_map(acc, [head | tail], function) do
do_map([function.(head) | acc], tail, function)
end
end
defmodule MyMap do
@doc """
iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
"""
def map(list, function) do
Enum.reverse do_map([], list, function)
end
defp do_map(acc, [], _function) do
acc
end
defp do_map(acc, [head | tail], function) do
do_map([function.(head) | acc], tail, function)
end
end
Ruby-like Syntax
Elixir & Phoenix – fast, concurrent and explicit
defmodule MyMap do
@doc """
iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
"""
def map(list, function) do
Enum.reverse do_map([], list, function)
end
defp do_map(acc, [], _function) do
acc
end
defp do_map(acc, [head | tail], function) do
do_map([function.(head) | acc], tail, function)
end
end
First-class functions
defmodule MyMap do
@doc """
iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
"""
def map(list, function) do
Enum.reverse do_map([], list, function)
end
defp do_map(acc, [], _function) do
acc
end
defp do_map(acc, [head | tail], function) do
do_map([function.(head) | acc], tail, function)
end
end
Tail-Call Optimization
defmodule MyMap do
@doc """
iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
"""
def map(list, function) do
Enum.reverse do_map([], list, function)
end
defp do_map(acc, [], _function) do
acc
end
defp do_map(acc, [head | tail], function) do
do_map([function.(head) | acc], tail, function)
end
end
Pattern Matching
defmodule Patterns do
def greet(%{name: name, age: age}) do
IO.puts "Hi there #{name}, what's up at #{age}?"
end
def greet(%{name: "Denis Defreyne"}) do
IO.puts "Hi Denis, are you all set for your talk?"
end
def greet(%{name: name}) do
IO.puts "Hi there #{name}"
end
def greet(_) do
IO.puts "Hi"
end
end
Patterns.greet %{name: "Tobi", age: 27, something: :else}
Patterns.greet %{name: "Denis Defreyne"}
Patterns.greet %{name: "Tobi"}
Patterns.greet ["Mop"]
Pattern Matching
defmodule Patterns do
def greet(%{name: name, age: age}) do
IO.puts "Hi there #{name}, what's up at #{age}?"
end
def greet(%{name: "Denis Defreyne"}) do
IO.puts "Hi Denis, are you all set for your talk?"
end
def greet(%{name: name}) do
IO.puts "Hi there #{name}"
end
def greet(_) do
IO.puts "Hi"
end
end
Patterns.greet %{name: "Tobi", age: 27, something: :else}
Patterns.greet %{name: "Denis Defreyne"}
Patterns.greet %{name: "Tobi"}
Patterns.greet ["Mop"]
Pattern Matching
defmodule Patterns do
def greet(%{name: name, age: age}) do
IO.puts "Hi there #{name}, what's up at #{age}?"
end
def greet(%{name: "Denis Defreyne"}) do
IO.puts "Hi Denis, are you all set for your talk?"
end
def greet(%{name: name}) do
IO.puts "Hi there #{name}"
end
def greet(_) do
IO.puts "Hi"
end
end
Patterns.greet %{name: "Tobi", age: 27, something: :else}
Patterns.greet %{name: "Denis Defreyne"}
Patterns.greet %{name: "Tobi"}
Patterns.greet ["Mop"]
Pattern Matching
defmodule Patterns do
def greet(%{name: name, age: age}) do
IO.puts "Hi there #{name}, what's up at #{age}?"
end
def greet(%{name: "Denis Defreyne"}) do
IO.puts "Hi Denis, are you all set for your talk?"
end
def greet(%{name: name}) do
IO.puts "Hi there #{name}"
end
def greet(_) do
IO.puts "Hi"
end
end
Patterns.greet %{name: "Tobi", age: 27, something: :else}
Patterns.greet %{name: "Denis Defreyne"}
Patterns.greet %{name: "Tobi"}
Patterns.greet ["Mop"]
Pattern Matching
defmodule Patterns do
def greet(%{name: name, age: age}) do
IO.puts "Hi there #{name}, what's up at #{age}?"
end
def greet(%{name: "Denis Defreyne"}) do
IO.puts "Hi Denis, are you all set for your talk?"
end
def greet(%{name: name}) do
IO.puts "Hi there #{name}"
end
def greet(_) do
IO.puts "Hi"
end
end
Patterns.greet %{name: "Tobi", age: 27, something: :else}
Patterns.greet %{name: "Denis Defreyne"}
Patterns.greet %{name: "Tobi"}
Patterns.greet ["Mop"]
Pattern Matching
defmodule MyMap do
@doc """
iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
"""
def map(list, function) do
Enum.reverse do_map([], list, function)
end
defp do_map(acc, [], _function) do
acc
end
defp do_map(acc, [head | tail], function) do
do_map([function.(head) | acc], tail, function)
end
end
Doctesting
defmacro plug(plug, opts  []) do
quote do
@plugs {unquote(plug), unquote(opts), true}
end
end
Meta Programming
defprotocol Blank do
@doc "Returns true if data is considered blank/empty"
def blank?(data)
end
defimpl Blank, for: List do
def blank?([]), do: true
def blank?(_), do: false
end
defimpl Blank, for: Map do
def blank?(map), do: map_size(map) == 0
end
defimpl Blank, for: Atom do
def blank?(false), do: true
def blank?(nil), do: true
def blank?(_), do: false
end
Polymorphism
defprotocol Blank do
@doc "Returns true if data is considered blank/empty"
def blank?(data)
end
defimpl Blank, for: List do
def blank?([]), do: true
def blank?(_), do: false
end
defimpl Blank, for: Map do
def blank?(map), do: map_size(map) == 0
end
defimpl Blank, for: Atom do
def blank?(false), do: true
def blank?(nil), do: true
def blank?(_), do: false
end
Polymorphism
defprotocol Blank do
@doc "Returns true if data is considered blank/empty"
def blank?(data)
end
defimpl Blank, for: List do
def blank?([]), do: true
def blank?(_), do: false
end
defimpl Blank, for: Map do
def blank?(map), do: map_size(map) == 0
end
defimpl Blank, for: Atom do
def blank?(false), do: true
def blank?(nil), do: true
def blank?(_), do: false
end
Polymorphism
@spec all?(t) :: boolean
@spec all?(t, (element -> as_boolean(term))) :: boolean
def all?(enumerable, fun  fn(x) -> x end)
def all?(enumerable, fun) when is_list(enumerable) and
is_function(fun, 1) do
do_all?(enumerable, fun)
end
Implemented in itself!
@spec all?(t) :: boolean
@spec all?(t, (element -> as_boolean(term))) :: boolean
def all?(enumerable, fun  fn(x) -> x end)
def all?(enumerable, fun) when is_list(enumerable) and
is_function(fun, 1) do
do_all?(enumerable, fun)
end
Optional Type Annotations
defmodule Plug do
@type opts :: tuple | atom | integer | float | [opts]
@callback init(opts) :: opts
@callback call(Plug.Conn.t, opts) :: Plug.Conn.t
end
“Interfaces”
defmodule Plug do
@type opts :: tuple | atom | integer | float | [opts]
@callback init(opts) :: opts
@callback call(Plug.Conn.t, opts) :: Plug.Conn.t
end
“Interfaces”
defmodule Plug.Head do
@behaviour Plug
alias Plug.Conn
def init([]), do: []
def call(%Conn{method: "HEAD"} = conn, []) do
%{conn | method: "GET"}
end
def call(conn, []), do: conn
end
“Interfaces”
defmodule Plug.Head do
@behaviour Plug
alias Plug.Conn
def init([]), do: []
def call(%Conn{method: "HEAD"} = conn, []) do
%{conn | method: "GET"}
end
def call(conn, []), do: conn
end
“Interfaces”
Functional Programming?
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
2.2.2 :001 > [1, 2, 3, 4].map { |i| i + 1 }
=> [2, 3, 4, 5]
iex(2)> Enum.map [1, 2, 3, 4], fn(i) -> i + 1 end
[2, 3, 4, 5]
vs
Where to call functions
Transformation
of Data
Pipe
people = DB.find_customers
orders = Orders.for_customers(people)
tax = sales_tax(orders, 2013)
filing = prepare_filing(tax)
filing = DB.find_customers
|> Orders.for_customers
|> sales_tax(2013)
|> prepare_filing
Pipe
filing =
prepare_filing(sales_tax(
Orders.for_cusstomers(DB.find_customers), 2013))
Pipe
filing = DB.find_customers
|> Orders.for_customers
|> sales_tax(2013)
|> prepare_filing
Pipe
person = Person.new(attributes)
do_something(person)
insert_in_db(person)
Immutable Data
person = Person.new(attributes)
person = do_something(person)
insert_in_db(person)
Immutable Data
Elixir & Phoenix – fast, concurrent and explicit
Principles vs Power
Minimize state
vs
Hiding state
Same Input,
Same Output
Testing++
Readability
First class actor support
OTP
Supervisors
Umbrella apps
Elixir & Phoenix – fast, concurrent and explicit
connection
|> endpoint
|> router
|> pipelines
|> controller
|> model
|> view
Flow
scope "/", Rumbl do
pipe_through :browser
get "/", PageController, :index
resources "/users", UserController,
only: [:index, :show, :new, :create]
resources "/sessions", SessionController,
only: [:new, :create, :delete]
get "/watch/:id", WatchController, :show
end
Routes
scope "/", Rumbl do
pipe_through :browser
get "/", PageController, :index
resources "/users", UserController,
only: [:index, :show, :new, :create]
resources "/sessions", SessionController,
only: [:new, :create, :delete]
get "/watch/:id", WatchController, :show
end
Routes
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug Rumbl.Auth, repo: Rumbl.Repo
end
pipeline :api do
plug :accepts, ["json"]
end
Pipelines
def new(conn, _params) do
changeset = User.new_changeset(%User{})
render conn, "new.html", changeset: changeset
end
Controller
defmodule Rumbl.User do
use Rumbl.Web, :model
schema "users" do
field :name, :string
field :username, :string
field :password, :string, virtual: true
field :password_hash, :string
has_many :videos, Rumbl.Video
timestamps
end
# ...
end
Model
defmodule Rumbl.UserView do
use Rumbl.Web, :view
alias Rumbl.User
def first_name(%{name: name}) do
name
|> String.split(" ")
|> Enum.at(0)
end
end
View
<%= form_for @changeset, user_path(@conn, :create), fn
form -> %>
<div class="form-group">
<%= text_input form, :name, placeholder: "Name",
class: "form-control" %>
<%= error_tag form, :name %>
</div>
<div class="form-group">
<%= text_input form, :username, placeholder:
"Username", class: "form-control" %>
<%= error_tag form, :username %>
</div>
<div class="form-group">
<%= password_input form, :password, placeholder:
"Password", class: "form-control" %>
<%= error_tag form, :password %>
</div>
<%= submit "Create User", class: "btn btn-primary" %>
<% end %>
Template
Elixir & Phoenix – fast, concurrent and explicit
def new_changeset(model, params  %{}) do
model
|> cast(params, ~w(name username), [])
|> unique_constraint(:username)
|> validate_length(:username, min: 1, max: 20)
end
def registration_changeset(model, params) do
model
|> new_changeset(params)
|> cast(params, ~w(password), [])
|> validate_length(:password, min: 6, max: 100)
|> put_pass_hash()
end
Changesets
def create(conn, %{"user" => user_params}) do
changeset = User.registration_changeset(%User{}, user_params)
case Repo.insert changeset do
{:ok, user} ->
conn
|> Rumbl.Auth.login(user)
|> put_flash(:info, "You successfully registered!")
|> redirect(to: user_path(conn, :index))
{:error, changeset}->
render conn, "new.html", changeset: changeset
end
end
Changesets
defmodule Rumbl.VideoChannel do
use Rumbl.Web, :channel
def join("videos:" <> video_id, _params, socket) do
{:ok, socket}
end
def handle_in("new_annotation", params, socket) do
broadcast! socket, "new_annotation", %{
user: %{username: "anon"},
body: params["body"],
at: params["at"]
}
{:reply, :ok, socket}
end
end
Channels
The right tool
iex(13)> user = Repo.get_by(User, name: "Homer")
iex(14)> user.videos
#Ecto.Association.NotLoaded<association :videos is not
loaded>
Explicit preloading
iex(13)> user = Repo.get_by(User, name: "Homer")
iex(14)> user.videos
#Ecto.Association.NotLoaded<association :videos is not
loaded>
Explicit preloading
iex(15)> Repo.preload(user, :videos)
iex(16)> user.videos
#Ecto.Association.NotLoaded<association :videos is not
loaded>
Explicit preloading
iex(17)> user = Repo.preload(user, :videos)
iex(18)> user.videos
[%Rumbl.Video{__meta__: #Ecto.Schema.Metadata<:loaded>,
category: #Ecto.Association.NotLoaded<association
:category is not loaded>,
category_id: nil, description: "such great many wow", id:
3,
inserted_at: #Ecto.DateTime<2016-02-28T18:42:41Z>, title:
"Hubidubiee",
updated_at: #Ecto.DateTime<2016-02-28T18:42:41Z>, url:
"www.lol.com",
user: #Ecto.Association.NotLoaded<association :user is
not loaded>,
user_id: 5}]
Explicit preloading
So we all go and do Elixir
and Phoenix now?
❤
Dirtiness
Baggage
Eco-System
A new land
So, would you start a
new project in Elixir and
Phoenix now?
Q&A question #1
IT 
DEPENDS
IT 
DEPENDS
Thanks & Enjoy Elixir
Tobias Pfeiffer
@PragTob
pragtob.info
Photo Attribution
● CC BY-ND 2.0
– https://www.flickr.com/photos/mmmswan/8918529543/
● CC BY 2.0
– https://flic.kr/p/eKGRRJ
● CC BY-NC 2.0
– https://www.flickr.com/photos/-jule/2728475835/
– https://flic.kr/p/emoKPd
● CC BY-NC-ND 2.0
– https://flic.kr/p/eyC7ZT
– https://www.flickr.com/photos/75487768@N04/14029339573/
– https://flic.kr/p/bG2r2D
● CC BY-SA 2.0
– https://commons.wikimedia.org/wiki/File:Heckert_GNU_white.svg
– https://flic.kr/p/cEJDC3

More Related Content

PDF
How fast ist it really? Benchmarking in practice
PDF
Palestra sobre Collections com Python
PDF
Pre-Bootcamp introduction to Elixir
PDF
Clustering com numpy e cython
PDF
PLOTCON NYC: Behind Every Great Plot There's a Great Deal of Wrangling
PDF
Let’s Talk About Ruby
PPTX
The groovy puzzlers (as Presented at JavaOne 2014)
PDF
The Ring programming language version 1.5.2 book - Part 45 of 181
How fast ist it really? Benchmarking in practice
Palestra sobre Collections com Python
Pre-Bootcamp introduction to Elixir
Clustering com numpy e cython
PLOTCON NYC: Behind Every Great Plot There's a Great Deal of Wrangling
Let’s Talk About Ruby
The groovy puzzlers (as Presented at JavaOne 2014)
The Ring programming language version 1.5.2 book - Part 45 of 181

What's hot (20)

PDF
Begin with Python
PDF
Go ahead, make my day
PDF
Codigos
PDF
Python for High School Programmers
PDF
Closures
PPT
Python tutorial
PDF
Intro to OTP in Elixir
PDF
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
ODP
PDF
Elixir pattern matching and recursion
ODP
The secrets of inverse brogramming
PDF
Python fundamentals - basic | WeiYuan
PPTX
Python chapter 2
PPTX
python chapter 1
PDF
Functional Pattern Matching on Python
PDF
mobl - model-driven engineering lecture
PDF
FPBrno 2018-05-22: Benchmarking in elixir
PDF
Groovy ネタ NGK 忘年会2009 ライトニングトーク
Begin with Python
Go ahead, make my day
Codigos
Python for High School Programmers
Closures
Python tutorial
Intro to OTP in Elixir
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Elixir pattern matching and recursion
The secrets of inverse brogramming
Python fundamentals - basic | WeiYuan
Python chapter 2
python chapter 1
Functional Pattern Matching on Python
mobl - model-driven engineering lecture
FPBrno 2018-05-22: Benchmarking in elixir
Groovy ネタ NGK 忘年会2009 ライトニングトーク
Ad

Viewers also liked (14)

PDF
What did AlphaGo do to beat the strongest human Go player?
PDF
Introducing Elixir the easy way
PDF
Elixir & Phoenix – fast, concurrent and explicit
PPT
Why Semantic Search Is Hard
PPTX
Test-Driven Development In Action
PDF
Test Driven Development
PDF
What did AlphaGo do to beat the strongest human Go player?
ODP
An Introduction To Shoes
PPTX
Test-Driven Development (TDD)
PPTX
暗号通貨勉強会
PPTX
簡単、クレカ決済! PAY.JPを使ったクレカ決済の仕組み・開発運用時の考慮点について
PDF
Test Driven Development (TDD)
PDF
The monad fear
PDF
Automated Web Testing using JavaScript
What did AlphaGo do to beat the strongest human Go player?
Introducing Elixir the easy way
Elixir & Phoenix – fast, concurrent and explicit
Why Semantic Search Is Hard
Test-Driven Development In Action
Test Driven Development
What did AlphaGo do to beat the strongest human Go player?
An Introduction To Shoes
Test-Driven Development (TDD)
暗号通貨勉強会
簡単、クレカ決済! PAY.JPを使ったクレカ決済の仕組み・開発運用時の考慮点について
Test Driven Development (TDD)
The monad fear
Automated Web Testing using JavaScript
Ad

Similar to Elixir & Phoenix – fast, concurrent and explicit (20)

PDF
Elixir & Phoenix - fast, concurrent and explicit
PDF
Introducing Elixir and OTP at the Erlang BASH
PDF
Elixir formatter Internals
KEY
Five Languages in a Moment
PDF
Ruby to Elixir - what's great and what you might miss
PPTX
Introducing Elixir
KEY
Tres Gemas De Ruby
KEY
Refactor like a boss
PDF
Functions, Types, Programs and Effects
PPTX
GE8151 Problem Solving and Python Programming
PDF
Is Haskell an acceptable Perl?
PDF
Something about Golang
PPTX
Groovy vs Boilerplate and Ceremony Code
PPT
Rails 2010 Workshop
KEY
An introduction to Ruby
PDF
KEY
Introduction to Groovy
PDF
Why async and functional programming in PHP7 suck and how to get overr it?
PDF
PDF
Elixir & Phoenix - fast, concurrent and explicit
Introducing Elixir and OTP at the Erlang BASH
Elixir formatter Internals
Five Languages in a Moment
Ruby to Elixir - what's great and what you might miss
Introducing Elixir
Tres Gemas De Ruby
Refactor like a boss
Functions, Types, Programs and Effects
GE8151 Problem Solving and Python Programming
Is Haskell an acceptable Perl?
Something about Golang
Groovy vs Boilerplate and Ceremony Code
Rails 2010 Workshop
An introduction to Ruby
Introduction to Groovy
Why async and functional programming in PHP7 suck and how to get overr it?

More from Tobias Pfeiffer (20)

PDF
Going Staff - Keynote @ CodeBEAM EU edition
PDF
Going Staff
PDF
Stories in Open SOurce
PDF
Metaphors are everywhere: Ideas to Improve Software Development
PDF
Stories in Open Source
PDF
Elixir & Phoenix – Fast, Concurrent and Explicit
PDF
Functioning Among Humans
PDF
Functioning Among Humans
PDF
Do You Need That Validation? Let Me Call You Back About It
PDF
Elixir, your Monolith and You
PDF
Where do Rubyists go?
PDF
It's About the Humans, Stupid (Lightning)
PDF
Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version)
PDF
Code, Comments, Concepts, Comprehension – Conclusion?
PDF
How fast is it really? Benchmarking in Practice (Ruby Version)
PDF
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...
PDF
Beating Go Thanks to the Power of Randomness
PDF
Optimizing For Readability
PDF
Code is read many mor times than written - short
PDF
Code is read many more times than written
Going Staff - Keynote @ CodeBEAM EU edition
Going Staff
Stories in Open SOurce
Metaphors are everywhere: Ideas to Improve Software Development
Stories in Open Source
Elixir & Phoenix – Fast, Concurrent and Explicit
Functioning Among Humans
Functioning Among Humans
Do You Need That Validation? Let Me Call You Back About It
Elixir, your Monolith and You
Where do Rubyists go?
It's About the Humans, Stupid (Lightning)
Stop Guessing and Start Measuring - Benchmarking Practice (Poly Version)
Code, Comments, Concepts, Comprehension – Conclusion?
How fast is it really? Benchmarking in Practice (Ruby Version)
What did AlphaGo do to beat the strongest human Go player? (Strange Group Ver...
Beating Go Thanks to the Power of Randomness
Optimizing For Readability
Code is read many mor times than written - short
Code is read many more times than written

Recently uploaded (20)

PDF
Spectral efficient network and resource selection model in 5G networks
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Empathic Computing: Creating Shared Understanding
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Unlocking AI with Model Context Protocol (MCP)
PPTX
sap open course for s4hana steps from ECC to s4
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PDF
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PPTX
Big Data Technologies - Introduction.pptx
PDF
MIND Revenue Release Quarter 2 2025 Press Release
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Building Integrated photovoltaic BIPV_UPV.pdf
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Encapsulation_ Review paper, used for researhc scholars
PDF
KodekX | Application Modernization Development
Spectral efficient network and resource selection model in 5G networks
“AI and Expert System Decision Support & Business Intelligence Systems”
Empathic Computing: Creating Shared Understanding
Per capita expenditure prediction using model stacking based on satellite ima...
The Rise and Fall of 3GPP – Time for a Sabbatical?
Unlocking AI with Model Context Protocol (MCP)
sap open course for s4hana steps from ECC to s4
Programs and apps: productivity, graphics, security and other tools
Advanced methodologies resolving dimensionality complications for autism neur...
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
Optimiser vos workloads AI/ML sur Amazon EC2 et AWS Graviton
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Big Data Technologies - Introduction.pptx
MIND Revenue Release Quarter 2 2025 Press Release
Reach Out and Touch Someone: Haptics and Empathic Computing
Building Integrated photovoltaic BIPV_UPV.pdf
Mobile App Security Testing_ A Comprehensive Guide.pdf
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Encapsulation_ Review paper, used for researhc scholars
KodekX | Application Modernization Development

Elixir & Phoenix – fast, concurrent and explicit

  • 7. Elixir and Phoenix fast, concurrent and explicit Tobias Pfeiffer @PragTob pragtob.info
  • 8. Elixir and Phoenix fast, concurrent and explicit Tobias Pfeiffer @PragTob pragtob.info
  • 11. defmodule MyMap do @doc """ iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] """ def map(list, function) do Enum.reverse do_map([], list, function) end defp do_map(acc, [], _function) do acc end defp do_map(acc, [head | tail], function) do do_map([function.(head) | acc], tail, function) end end
  • 12. defmodule MyMap do @doc """ iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] """ def map(list, function) do Enum.reverse do_map([], list, function) end defp do_map(acc, [], _function) do acc end defp do_map(acc, [head | tail], function) do do_map([function.(head) | acc], tail, function) end end Ruby-like Syntax
  • 14. defmodule MyMap do @doc """ iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] """ def map(list, function) do Enum.reverse do_map([], list, function) end defp do_map(acc, [], _function) do acc end defp do_map(acc, [head | tail], function) do do_map([function.(head) | acc], tail, function) end end First-class functions
  • 15. defmodule MyMap do @doc """ iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] """ def map(list, function) do Enum.reverse do_map([], list, function) end defp do_map(acc, [], _function) do acc end defp do_map(acc, [head | tail], function) do do_map([function.(head) | acc], tail, function) end end Tail-Call Optimization
  • 16. defmodule MyMap do @doc """ iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] """ def map(list, function) do Enum.reverse do_map([], list, function) end defp do_map(acc, [], _function) do acc end defp do_map(acc, [head | tail], function) do do_map([function.(head) | acc], tail, function) end end Pattern Matching
  • 17. defmodule Patterns do def greet(%{name: name, age: age}) do IO.puts "Hi there #{name}, what's up at #{age}?" end def greet(%{name: "Denis Defreyne"}) do IO.puts "Hi Denis, are you all set for your talk?" end def greet(%{name: name}) do IO.puts "Hi there #{name}" end def greet(_) do IO.puts "Hi" end end Patterns.greet %{name: "Tobi", age: 27, something: :else} Patterns.greet %{name: "Denis Defreyne"} Patterns.greet %{name: "Tobi"} Patterns.greet ["Mop"] Pattern Matching
  • 18. defmodule Patterns do def greet(%{name: name, age: age}) do IO.puts "Hi there #{name}, what's up at #{age}?" end def greet(%{name: "Denis Defreyne"}) do IO.puts "Hi Denis, are you all set for your talk?" end def greet(%{name: name}) do IO.puts "Hi there #{name}" end def greet(_) do IO.puts "Hi" end end Patterns.greet %{name: "Tobi", age: 27, something: :else} Patterns.greet %{name: "Denis Defreyne"} Patterns.greet %{name: "Tobi"} Patterns.greet ["Mop"] Pattern Matching
  • 19. defmodule Patterns do def greet(%{name: name, age: age}) do IO.puts "Hi there #{name}, what's up at #{age}?" end def greet(%{name: "Denis Defreyne"}) do IO.puts "Hi Denis, are you all set for your talk?" end def greet(%{name: name}) do IO.puts "Hi there #{name}" end def greet(_) do IO.puts "Hi" end end Patterns.greet %{name: "Tobi", age: 27, something: :else} Patterns.greet %{name: "Denis Defreyne"} Patterns.greet %{name: "Tobi"} Patterns.greet ["Mop"] Pattern Matching
  • 20. defmodule Patterns do def greet(%{name: name, age: age}) do IO.puts "Hi there #{name}, what's up at #{age}?" end def greet(%{name: "Denis Defreyne"}) do IO.puts "Hi Denis, are you all set for your talk?" end def greet(%{name: name}) do IO.puts "Hi there #{name}" end def greet(_) do IO.puts "Hi" end end Patterns.greet %{name: "Tobi", age: 27, something: :else} Patterns.greet %{name: "Denis Defreyne"} Patterns.greet %{name: "Tobi"} Patterns.greet ["Mop"] Pattern Matching
  • 21. defmodule Patterns do def greet(%{name: name, age: age}) do IO.puts "Hi there #{name}, what's up at #{age}?" end def greet(%{name: "Denis Defreyne"}) do IO.puts "Hi Denis, are you all set for your talk?" end def greet(%{name: name}) do IO.puts "Hi there #{name}" end def greet(_) do IO.puts "Hi" end end Patterns.greet %{name: "Tobi", age: 27, something: :else} Patterns.greet %{name: "Denis Defreyne"} Patterns.greet %{name: "Tobi"} Patterns.greet ["Mop"] Pattern Matching
  • 22. defmodule MyMap do @doc """ iex> MyMap.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] """ def map(list, function) do Enum.reverse do_map([], list, function) end defp do_map(acc, [], _function) do acc end defp do_map(acc, [head | tail], function) do do_map([function.(head) | acc], tail, function) end end Doctesting
  • 23. defmacro plug(plug, opts []) do quote do @plugs {unquote(plug), unquote(opts), true} end end Meta Programming
  • 24. defprotocol Blank do @doc "Returns true if data is considered blank/empty" def blank?(data) end defimpl Blank, for: List do def blank?([]), do: true def blank?(_), do: false end defimpl Blank, for: Map do def blank?(map), do: map_size(map) == 0 end defimpl Blank, for: Atom do def blank?(false), do: true def blank?(nil), do: true def blank?(_), do: false end Polymorphism
  • 25. defprotocol Blank do @doc "Returns true if data is considered blank/empty" def blank?(data) end defimpl Blank, for: List do def blank?([]), do: true def blank?(_), do: false end defimpl Blank, for: Map do def blank?(map), do: map_size(map) == 0 end defimpl Blank, for: Atom do def blank?(false), do: true def blank?(nil), do: true def blank?(_), do: false end Polymorphism
  • 26. defprotocol Blank do @doc "Returns true if data is considered blank/empty" def blank?(data) end defimpl Blank, for: List do def blank?([]), do: true def blank?(_), do: false end defimpl Blank, for: Map do def blank?(map), do: map_size(map) == 0 end defimpl Blank, for: Atom do def blank?(false), do: true def blank?(nil), do: true def blank?(_), do: false end Polymorphism
  • 27. @spec all?(t) :: boolean @spec all?(t, (element -> as_boolean(term))) :: boolean def all?(enumerable, fun fn(x) -> x end) def all?(enumerable, fun) when is_list(enumerable) and is_function(fun, 1) do do_all?(enumerable, fun) end Implemented in itself!
  • 28. @spec all?(t) :: boolean @spec all?(t, (element -> as_boolean(term))) :: boolean def all?(enumerable, fun fn(x) -> x end) def all?(enumerable, fun) when is_list(enumerable) and is_function(fun, 1) do do_all?(enumerable, fun) end Optional Type Annotations
  • 29. defmodule Plug do @type opts :: tuple | atom | integer | float | [opts] @callback init(opts) :: opts @callback call(Plug.Conn.t, opts) :: Plug.Conn.t end “Interfaces”
  • 30. defmodule Plug do @type opts :: tuple | atom | integer | float | [opts] @callback init(opts) :: opts @callback call(Plug.Conn.t, opts) :: Plug.Conn.t end “Interfaces”
  • 31. defmodule Plug.Head do @behaviour Plug alias Plug.Conn def init([]), do: [] def call(%Conn{method: "HEAD"} = conn, []) do %{conn | method: "GET"} end def call(conn, []), do: conn end “Interfaces”
  • 32. defmodule Plug.Head do @behaviour Plug alias Plug.Conn def init([]), do: [] def call(%Conn{method: "HEAD"} = conn, []) do %{conn | method: "GET"} end def call(conn, []), do: conn end “Interfaces”
  • 37. 2.2.2 :001 > [1, 2, 3, 4].map { |i| i + 1 } => [2, 3, 4, 5] iex(2)> Enum.map [1, 2, 3, 4], fn(i) -> i + 1 end [2, 3, 4, 5] vs Where to call functions
  • 39. Pipe people = DB.find_customers orders = Orders.for_customers(people) tax = sales_tax(orders, 2013) filing = prepare_filing(tax)
  • 40. filing = DB.find_customers |> Orders.for_customers |> sales_tax(2013) |> prepare_filing Pipe
  • 42. filing = DB.find_customers |> Orders.for_customers |> sales_tax(2013) |> prepare_filing Pipe
  • 44. person = Person.new(attributes) person = do_something(person) insert_in_db(person) Immutable Data
  • 51. First class actor support
  • 52. OTP
  • 56. connection |> endpoint |> router |> pipelines |> controller |> model |> view Flow
  • 57. scope "/", Rumbl do pipe_through :browser get "/", PageController, :index resources "/users", UserController, only: [:index, :show, :new, :create] resources "/sessions", SessionController, only: [:new, :create, :delete] get "/watch/:id", WatchController, :show end Routes
  • 58. scope "/", Rumbl do pipe_through :browser get "/", PageController, :index resources "/users", UserController, only: [:index, :show, :new, :create] resources "/sessions", SessionController, only: [:new, :create, :delete] get "/watch/:id", WatchController, :show end Routes
  • 59. pipeline :browser do plug :accepts, ["html"] plug :fetch_session plug :fetch_flash plug :protect_from_forgery plug :put_secure_browser_headers plug Rumbl.Auth, repo: Rumbl.Repo end pipeline :api do plug :accepts, ["json"] end Pipelines
  • 60. def new(conn, _params) do changeset = User.new_changeset(%User{}) render conn, "new.html", changeset: changeset end Controller
  • 61. defmodule Rumbl.User do use Rumbl.Web, :model schema "users" do field :name, :string field :username, :string field :password, :string, virtual: true field :password_hash, :string has_many :videos, Rumbl.Video timestamps end # ... end Model
  • 62. defmodule Rumbl.UserView do use Rumbl.Web, :view alias Rumbl.User def first_name(%{name: name}) do name |> String.split(" ") |> Enum.at(0) end end View
  • 63. <%= form_for @changeset, user_path(@conn, :create), fn form -> %> <div class="form-group"> <%= text_input form, :name, placeholder: "Name", class: "form-control" %> <%= error_tag form, :name %> </div> <div class="form-group"> <%= text_input form, :username, placeholder: "Username", class: "form-control" %> <%= error_tag form, :username %> </div> <div class="form-group"> <%= password_input form, :password, placeholder: "Password", class: "form-control" %> <%= error_tag form, :password %> </div> <%= submit "Create User", class: "btn btn-primary" %> <% end %> Template
  • 65. def new_changeset(model, params %{}) do model |> cast(params, ~w(name username), []) |> unique_constraint(:username) |> validate_length(:username, min: 1, max: 20) end def registration_changeset(model, params) do model |> new_changeset(params) |> cast(params, ~w(password), []) |> validate_length(:password, min: 6, max: 100) |> put_pass_hash() end Changesets
  • 66. def create(conn, %{"user" => user_params}) do changeset = User.registration_changeset(%User{}, user_params) case Repo.insert changeset do {:ok, user} -> conn |> Rumbl.Auth.login(user) |> put_flash(:info, "You successfully registered!") |> redirect(to: user_path(conn, :index)) {:error, changeset}-> render conn, "new.html", changeset: changeset end end Changesets
  • 67. defmodule Rumbl.VideoChannel do use Rumbl.Web, :channel def join("videos:" <> video_id, _params, socket) do {:ok, socket} end def handle_in("new_annotation", params, socket) do broadcast! socket, "new_annotation", %{ user: %{username: "anon"}, body: params["body"], at: params["at"] } {:reply, :ok, socket} end end Channels
  • 69. iex(13)> user = Repo.get_by(User, name: "Homer") iex(14)> user.videos #Ecto.Association.NotLoaded<association :videos is not loaded> Explicit preloading
  • 70. iex(13)> user = Repo.get_by(User, name: "Homer") iex(14)> user.videos #Ecto.Association.NotLoaded<association :videos is not loaded> Explicit preloading
  • 71. iex(15)> Repo.preload(user, :videos) iex(16)> user.videos #Ecto.Association.NotLoaded<association :videos is not loaded> Explicit preloading
  • 72. iex(17)> user = Repo.preload(user, :videos) iex(18)> user.videos [%Rumbl.Video{__meta__: #Ecto.Schema.Metadata<:loaded>, category: #Ecto.Association.NotLoaded<association :category is not loaded>, category_id: nil, description: "such great many wow", id: 3, inserted_at: #Ecto.DateTime<2016-02-28T18:42:41Z>, title: "Hubidubiee", updated_at: #Ecto.DateTime<2016-02-28T18:42:41Z>, url: "www.lol.com", user: #Ecto.Association.NotLoaded<association :user is not loaded>, user_id: 5}] Explicit preloading
  • 73. So we all go and do Elixir and Phoenix now?
  • 74.
  • 79. So, would you start a new project in Elixir and Phoenix now? Q&A question #1
  • 82. Thanks & Enjoy Elixir Tobias Pfeiffer @PragTob pragtob.info
  • 83. Photo Attribution ● CC BY-ND 2.0 – https://www.flickr.com/photos/mmmswan/8918529543/ ● CC BY 2.0 – https://flic.kr/p/eKGRRJ ● CC BY-NC 2.0 – https://www.flickr.com/photos/-jule/2728475835/ – https://flic.kr/p/emoKPd ● CC BY-NC-ND 2.0 – https://flic.kr/p/eyC7ZT – https://www.flickr.com/photos/75487768@N04/14029339573/ – https://flic.kr/p/bG2r2D ● CC BY-SA 2.0 – https://commons.wikimedia.org/wiki/File:Heckert_GNU_white.svg – https://flic.kr/p/cEJDC3