SlideShare a Scribd company logo
Elixir and Phoenix
fast, concurrent and explicit
Tobias Pfeiffer
@PragTob
pragtob.info
Elixir and Phoenix
fast, concurrent and explicit
Tobias Pfeiffer
@PragTob
pragtob.info
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
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?
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
Principles vs Power
Minimize state
vs
Hiding state
Same Input,
Same Output
Testing++
Readability
First class actor support
OTP
Supervisors
Umbrella apps
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
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

What's hot

Begin with Python
Begin with PythonBegin with Python
Begin with Python
Narong Intiruk
 
Slides
SlidesSlides
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
Tor Ivry
 
Codigos
CodigosCodigos
Codigos
Brian Joseff
 
Python for High School Programmers
Python for High School ProgrammersPython for High School Programmers
Python for High School Programmers
Siva Arunachalam
 
Closures
ClosuresClosures
Closures
SV.CO
 
Python tutorial
Python tutorialPython tutorial
Python tutorial
AllsoftSolutions
 
Intro to OTP in Elixir
Intro to OTP in ElixirIntro to OTP in Elixir
Intro to OTP in Elixir
Jesse Anderson
 
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Tobias Pfeiffer
 
Intro
IntroIntro
Elixir pattern matching and recursion
Elixir pattern matching and recursionElixir pattern matching and recursion
Elixir pattern matching and recursion
Bob Firestone
 
Py3k
Py3kPy3k
The secrets of inverse brogramming
The secrets of inverse brogrammingThe secrets of inverse brogramming
The secrets of inverse brogramming
Richie Cotton
 
Python fundamentals - basic | WeiYuan
Python fundamentals - basic | WeiYuanPython fundamentals - basic | WeiYuan
Python fundamentals - basic | WeiYuan
Wei-Yuan Chang
 
Python chapter 2
Python chapter 2Python chapter 2
Python chapter 2
Raghu nath
 
python chapter 1
python chapter 1python chapter 1
python chapter 1
Raghu nath
 
Functional Pattern Matching on Python
Functional Pattern Matching on PythonFunctional Pattern Matching on Python
Functional Pattern Matching on Python
Daker Fernandes
 
mobl - model-driven engineering lecture
mobl - model-driven engineering lecturemobl - model-driven engineering lecture
mobl - model-driven engineering lecture
zefhemel
 
FPBrno 2018-05-22: Benchmarking in elixir
FPBrno 2018-05-22: Benchmarking in elixirFPBrno 2018-05-22: Benchmarking in elixir
FPBrno 2018-05-22: Benchmarking in elixir
Functional Programming Brno
 
Groovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトークGroovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトーク
Tsuyoshi Yamamoto
 

What's hot (20)

Begin with Python
Begin with PythonBegin with Python
Begin with Python
 
Slides
SlidesSlides
Slides
 
Go ahead, make my day
Go ahead, make my dayGo ahead, make my day
Go ahead, make my day
 
Codigos
CodigosCodigos
Codigos
 
Python for High School Programmers
Python for High School ProgrammersPython for High School Programmers
Python for High School Programmers
 
Closures
ClosuresClosures
Closures
 
Python tutorial
Python tutorialPython tutorial
Python tutorial
 
Intro to OTP in Elixir
Intro to OTP in ElixirIntro to OTP in Elixir
Intro to OTP in Elixir
 
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
Stop Guessing and Start Measuring - Benchmarking in Practice (Lambdadays)
 
Intro
IntroIntro
Intro
 
Elixir pattern matching and recursion
Elixir pattern matching and recursionElixir pattern matching and recursion
Elixir pattern matching and recursion
 
Py3k
Py3kPy3k
Py3k
 
The secrets of inverse brogramming
The secrets of inverse brogrammingThe secrets of inverse brogramming
The secrets of inverse brogramming
 
Python fundamentals - basic | WeiYuan
Python fundamentals - basic | WeiYuanPython fundamentals - basic | WeiYuan
Python fundamentals - basic | WeiYuan
 
Python chapter 2
Python chapter 2Python chapter 2
Python chapter 2
 
python chapter 1
python chapter 1python chapter 1
python chapter 1
 
Functional Pattern Matching on Python
Functional Pattern Matching on PythonFunctional Pattern Matching on Python
Functional Pattern Matching on Python
 
mobl - model-driven engineering lecture
mobl - model-driven engineering lecturemobl - model-driven engineering lecture
mobl - model-driven engineering lecture
 
FPBrno 2018-05-22: Benchmarking in elixir
FPBrno 2018-05-22: Benchmarking in elixirFPBrno 2018-05-22: Benchmarking in elixir
FPBrno 2018-05-22: Benchmarking in elixir
 
Groovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトークGroovy ネタ NGK 忘年会2009 ライトニングトーク
Groovy ネタ NGK 忘年会2009 ライトニングトーク
 

Viewers also liked

What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?
Tobias Pfeiffer
 
Introducing Elixir the easy way
Introducing Elixir the easy wayIntroducing Elixir the easy way
Introducing Elixir the easy way
Tobias Pfeiffer
 
Elixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicitElixir & Phoenix – fast, concurrent and explicit
Elixir & Phoenix – fast, concurrent and explicit
Tobias Pfeiffer
 
Why Semantic Search Is Hard
Why Semantic Search Is HardWhy Semantic Search Is Hard
Why Semantic Search Is Hard
Truevert
 
Test-Driven Development In Action
Test-Driven Development In ActionTest-Driven Development In Action
Test-Driven Development In Action
Jon Kruger
 
Test Driven Development
Test Driven DevelopmentTest Driven Development
Test Driven Development
jakubkoci
 
What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?What did AlphaGo do to beat the strongest human Go player?
What did AlphaGo do to beat the strongest human Go player?
Tobias Pfeiffer
 
An Introduction To Shoes
An Introduction To ShoesAn Introduction To Shoes
An Introduction To Shoes
Tobias Pfeiffer
 
Test-Driven Development (TDD)
Test-Driven Development (TDD)Test-Driven Development (TDD)
Test-Driven Development (TDD)
Brian Rasmussen
 
暗号通貨勉強会
暗号通貨勉強会暗号通貨勉強会
暗号通貨勉強会
Kohei Ogawa
 
簡単、クレカ決済! PAY.JPを使ったクレカ決済の仕組み・開発運用時の考慮点について
簡単、クレカ決済! PAY.JPを使ったクレカ決済の仕組み・開発運用時の考慮点について簡単、クレカ決済! PAY.JPを使ったクレカ決済の仕組み・開発運用時の考慮点について
簡単、クレカ決済! PAY.JPを使ったクレカ決済の仕組み・開発運用時の考慮点について
dcubeio
 
Test Driven Development (TDD)
Test Driven Development (TDD)Test Driven Development (TDD)
Test Driven Development (TDD)
David Ehringer
 
The monad fear
The monad fearThe monad fear
The monad fear
LINE Corporation
 
Automated Web Testing using JavaScript
Automated Web Testing using JavaScriptAutomated Web Testing using JavaScript
Automated Web Testing using JavaScript
Simon Guest
 

Viewers also liked (14)

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

Similar to Elixir & Phoenix – fast, concurrent and explicit

Elixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicitElixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicit
Tobias Pfeiffer
 
Introducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASHIntroducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASH
devbash
 
Elixir formatter Internals
Elixir formatter InternalsElixir formatter Internals
Elixir formatter Internals
Pedro Medeiros
 
Five Languages in a Moment
Five Languages in a MomentFive Languages in a Moment
Five Languages in a Moment
Sergio Gil
 
Ruby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might missRuby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might miss
Tobias Pfeiffer
 
Introducing Elixir
Introducing ElixirIntroducing Elixir
Introducing Elixir
Abdulsattar Mohammed
 
Tres Gemas De Ruby
Tres Gemas De RubyTres Gemas De Ruby
Tres Gemas De Ruby
Leonardo Soto
 
Refactor like a boss
Refactor like a bossRefactor like a boss
Refactor like a boss
gsterndale
 
Functions, Types, Programs and Effects
Functions, Types, Programs and EffectsFunctions, Types, Programs and Effects
Functions, Types, Programs and Effects
Raymond Roestenburg
 
GE8151 Problem Solving and Python Programming
GE8151 Problem Solving and Python ProgrammingGE8151 Problem Solving and Python Programming
GE8151 Problem Solving and Python Programming
Muthu Vinayagam
 
Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?
osfameron
 
Something about Golang
Something about GolangSomething about Golang
Something about Golang
Anton Arhipov
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Code
stasimus
 
Rails 2010 Workshop
Rails 2010 WorkshopRails 2010 Workshop
Rails 2010 Workshop
dtsadok
 
An introduction to Ruby
An introduction to RubyAn introduction to Ruby
An introduction to Ruby
Wes Oldenbeuving
 
Erlang
ErlangErlang
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
André Faria Gomes
 
Why async and functional programming in PHP7 suck and how to get overr it?
Why async and functional programming in PHP7 suck and how to get overr it?Why async and functional programming in PHP7 suck and how to get overr it?
Why async and functional programming in PHP7 suck and how to get overr it?
Lucas Witold Adamus
 
Basics
BasicsBasics
Python slide
Python slidePython slide

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

Elixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicitElixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicit
 
Introducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASHIntroducing Elixir and OTP at the Erlang BASH
Introducing Elixir and OTP at the Erlang BASH
 
Elixir formatter Internals
Elixir formatter InternalsElixir formatter Internals
Elixir formatter Internals
 
Five Languages in a Moment
Five Languages in a MomentFive Languages in a Moment
Five Languages in a Moment
 
Ruby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might missRuby to Elixir - what's great and what you might miss
Ruby to Elixir - what's great and what you might miss
 
Introducing Elixir
Introducing ElixirIntroducing Elixir
Introducing Elixir
 
Tres Gemas De Ruby
Tres Gemas De RubyTres Gemas De Ruby
Tres Gemas De Ruby
 
Refactor like a boss
Refactor like a bossRefactor like a boss
Refactor like a boss
 
Functions, Types, Programs and Effects
Functions, Types, Programs and EffectsFunctions, Types, Programs and Effects
Functions, Types, Programs and Effects
 
GE8151 Problem Solving and Python Programming
GE8151 Problem Solving and Python ProgrammingGE8151 Problem Solving and Python Programming
GE8151 Problem Solving and Python Programming
 
Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?Is Haskell an acceptable Perl?
Is Haskell an acceptable Perl?
 
Something about Golang
Something about GolangSomething about Golang
Something about Golang
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Code
 
Rails 2010 Workshop
Rails 2010 WorkshopRails 2010 Workshop
Rails 2010 Workshop
 
An introduction to Ruby
An introduction to RubyAn introduction to Ruby
An introduction to Ruby
 
Erlang
ErlangErlang
Erlang
 
Introduction to Groovy
Introduction to GroovyIntroduction to Groovy
Introduction to Groovy
 
Why async and functional programming in PHP7 suck and how to get overr it?
Why async and functional programming in PHP7 suck and how to get overr it?Why async and functional programming in PHP7 suck and how to get overr it?
Why async and functional programming in PHP7 suck and how to get overr it?
 
Basics
BasicsBasics
Basics
 
Python slide
Python slidePython slide
Python slide
 

More from Tobias Pfeiffer

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

More from Tobias Pfeiffer (20)

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

Recently uploaded

By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024
Pierluigi Pugliese
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems S.M.S.A.
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
Zilliz
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
Aftab Hussain
 
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
Neo4j
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
Matthew Sinclair
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
Kari Kakkonen
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
Matthew Sinclair
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
James Anderson
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
DianaGray10
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
Safe Software
 
How to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptxHow to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptx
danishmna97
 
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AIEnchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Vladimir Iglovikov, Ph.D.
 
Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1
DianaGray10
 
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
Neo4j
 
Artificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopmentArtificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopment
Octavian Nadolu
 
GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...
ThomasParaiso2
 
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
Neo4j
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
Neo4j
 

Recently uploaded (20)

By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024By Design, not by Accident - Agile Venture Bolzano 2024
By Design, not by Accident - Agile Venture Bolzano 2024
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
Uni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdfUni Systems Copilot event_05062024_C.Vlachos.pdf
Uni Systems Copilot event_05062024_C.Vlachos.pdf
 
Full-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalizationFull-RAG: A modern architecture for hyper-personalization
Full-RAG: A modern architecture for hyper-personalization
 
Removing Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software FuzzingRemoving Uninteresting Bytes in Software Fuzzing
Removing Uninteresting Bytes in Software Fuzzing
 
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...
 
20240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 202420240607 QFM018 Elixir Reading List May 2024
20240607 QFM018 Elixir Reading List May 2024
 
Climate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing DaysClimate Impact of Software Testing at Nordic Testing Days
Climate Impact of Software Testing at Nordic Testing Days
 
20240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 202420240609 QFM020 Irresponsible AI Reading List May 2024
20240609 QFM020 Irresponsible AI Reading List May 2024
 
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
GDG Cloud Southlake #33: Boule & Rebala: Effective AppSec in SDLC using Deplo...
 
UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6UiPath Test Automation using UiPath Test Suite series, part 6
UiPath Test Automation using UiPath Test Suite series, part 6
 
Essentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FMEEssentials of Automations: The Art of Triggers and Actions in FME
Essentials of Automations: The Art of Triggers and Actions in FME
 
How to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptxHow to Get CNIC Information System with Paksim Ga.pptx
How to Get CNIC Information System with Paksim Ga.pptx
 
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AIEnchancing adoption of Open Source Libraries. A case study on Albumentations.AI
Enchancing adoption of Open Source Libraries. A case study on Albumentations.AI
 
Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1Communications Mining Series - Zero to Hero - Session 1
Communications Mining Series - Zero to Hero - Session 1
 
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
GraphSummit Singapore | Enhancing Changi Airport Group's Passenger Experience...
 
Artificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopmentArtificial Intelligence for XMLDevelopment
Artificial Intelligence for XMLDevelopment
 
GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...GridMate - End to end testing is a critical piece to ensure quality and avoid...
GridMate - End to end testing is a critical piece to ensure quality and avoid...
 
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
GraphSummit Singapore | Graphing Success: Revolutionising Organisational Stru...
 
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024GraphSummit Singapore | The Art of the  Possible with Graph - Q2 2024
GraphSummit Singapore | The Art of the Possible with Graph - Q2 2024
 

Elixir & Phoenix – fast, concurrent and explicit

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 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
  • 9.
  • 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
  • 13.
  • 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”
  • 34.
  • 35.
  • 36.
  • 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
  • 45.
  • 51. First class actor support
  • 52. OTP
  • 55.
  • 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
  • 64.
  • 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