SlideShare a Scribd company logo
1 of 68
Download to read offline
Elixir and OTP
Chris McGrath
@chrismcg
chris@chrismcg.com
What is Elixir?
Elixir
Elixir is a dynamic, functional language designed for building
scalable and maintainable applications.
Elixir leverages the Erlang VM, known for running low-latency,
distributed and fault-tolerant systems, while also being
successfully used in web development and the embedded
software domain.
— http://www.elixir-lang.org
What Elixir is NOT
• Some sort of CoffeeScript for Erlang
• A port of Ruby to Erlang
• Just Erlang with nicer syntax
Some example code
defmodule RedirectCounter.URL do
@max_redirects 10
def count_redirects(url) do
{ :ok, response } = HTTPoison.head(url)
do_count(response.status_code, response.headers["Location"], 0)
end
defp do_count(_status_code, _url, @max_redirects), do: raise "To many redirects"
defp do_count(status_code, url, redirect_count) when status_code in [301, 302, 307] do
{ :ok, response } = HTTPoison.head(url)
do_count(response.status_code, response.headers["Location"], redirect_count + 1)
end
defp do_count(_status_code, _url, redirect_count), do: redirect_count
end
Why learn Elixir?
Personal Reasons
"Boss" Reasons
• Our systems are becoming more and more parallel and the
primitives provided by most languages are quite low level
• Runs on top of the Erlang runtime, famous for amazing
uptimes and fault tolerance
• Powerful macro system for creating DSLs and reducing
boilerplate
• OTP library and architecture makes it easier to create fault
tolerant systems
What's Elixir useful for?
• Network related tasks (from plain sockets to web servers
and frameworks)
• Writing reliable, distributed, and highly available software
• MMO backends (not frontends!)
• Using all the cores
• (AKA Things Erlang Is Good For)
What Elixir adds to Erlang
• Modules for namespacing
• Macros
• A focus on tooling
• Streaming
What Elixir adds to Erlang
• Much nicer string handling
• Consistent function parameters
• Clearer organization of standard library
• Variable rebinding
• Less fiddly syntax
Language Highlights
• Mix project management tool
• First class documentation and doctests
• Toll free calling of Erlang functions
• Macros
• Pipeline Operator
• Protocols
Mix
• Generates and manages projects
• Somewhat similar to leiningen
• Like Make/Rake it can compile and runs tests
• Like Bundler it allows dependencies to be specified
• Like Rails or Bundler it can generate new project skeletons
• Full integration with Erlang, Rebar, and hex.pm
IEx - Interactive Elixir REPL
% iex
iex(1)> x = 1 + 2
3
iex(2)> x = 4
4
iex(3)> IO.puts "Hello World"
Hello World
:ok
Documentation & Doctests
defmodule ShowDoctest do
@moduledoc """
This module shows off an example of a doctest
"""
@doc """
Adds it's inputs together
iex> ShowDoctest.add(1, 1)
2
"""
def add(a, b) do
a - b
end
end
defmodule ShowDoctestTest do
use ExUnit.Case, async: true
doctest ShowDoctest
end
% mix test
1) test doc at ShowDoctest.add/2 (1) (ShowDoctestTest)
test/show_doctest_test.exs:3
Doctest failed
code: ShowDoctest.add(1, 1) === 2
lhs: 0
stacktrace:
lib/show_doctest.ex:12: ShowDoctest (module)
IEx Doc integration
% iex -S mix
iex(1)> h ShowDoctest
ShowDoctest
This module shows off an example of a doctest
iex(2)> h ShowDoctest.add
def add(a, b)
Adds it's inputs together
Toll free calling into erlang
You can use any available Erlang library in your Elixir project
% erl
Eshell V6.3 (abort with ^G)
1> os:timestamp().
{1422,119363,162867}
% iex
iex(1)> :os.timestamp
{1422, 119376, 391592}
Macros
Lisps traditionally empowered developers because you can
eliminate anything that's tedious through macros, and that power
is really what people keep going back for
— Rich Hickey
Macro Example
test "some sums" do
assert 1 + 1 == 3
end
1) test some math (TestProjectTest)
** (ExUnit.ExpectationError)
expected: 2
to be equal to (==): 3
at test/test_project_test.exs:5
Macro Example
iex(1)> quote do: 1 + 1 == 3
{:==, [context: Elixir, import: Kernel],
[{:+, [context: Elixir, import: Kernel], [1, 1]}, 3]}
defmacro assert({ :==, _, [l, r]}) do
# ...
end
defmacro assert({ :=~, _, [l, r]}) do
# ...
end
Pipelines
people = DB.find_customers
orders = Orders.for_customers(people)
tax = sales_tax(orders, 2013)
filing = prepare_filing(tax)
Pipelines
filing = DB.find_customers
|> Orders.for_customers
|> sales_tax(2013)
|> prepare_filing
Pipelines
# rewritten to...
filing = prepare_filing(
sales_tax(
Orders.for_customers(DB.find_customers),
2013
))
Protocols
• Let you have polymorphism in Elixir
• Inspired heavily by Clojure
• Can define implementation of built in protocols for your
own types
Protocols: Definition1
defprotocol Blank do
@doc "Returns true if data is considered blank/empty"
def blank?(data)
end
1
Sorry, the syntax highlighter doesn't know about protocols yet
Protocols: Implementation1
# Integers are never blank
defimpl Blank, for: Integer do
def blank?(_), do: false
end
# Just empty list is blank
defimpl Blank, for: List do
def blank?([]), do: true
def blank?(_), do: false
end
#...
1
Sorry, the syntax highlighter doesn't know about protocols yet
Protocols: Calling
iex> Blank.blank?(0)
false
iex> Blank.blank?([])
true
iex> Blank.blank?([1, 2, 3])
false
Enumerable
iex(1)> Enum.map([1, 2, 3], fn(x) -> x * x end)
[1, 4, 9]
iex(2)> Enum.map([1, 2, 3], &(&1 * &1))
[1, 4, 9]
Enumerable
iex(1)> stream = Stream.map([1, 2, 3], &(&1 * &1))
#Stream<[enum: [1, 2, 3], funs: [#Function<45.29647706/1 in Stream.map/2>]]>
iex(2)> stream = Stream.map(stream, &Integer.to_string/1)
#Stream<[enum: [1, 2, 3],
funs: [#Function<45.29647706/1 in Stream.map/2>,
#Function<45.29647706/1 in Stream.map/2>]]>
iex(3)> Enum.to_list(stream)
["1", "4", "9"]
# More example code
defmodule RedirectCounter.Twitter do
def configure do
# ... boring setup ...
end
def links do
configure
ExTwitter.stream_filter(track: "link")
|> Stream.reject(fn(t) -> t.entities["urls"] == [] end)
|> Stream.flat_map(fn(t) ->
Enum.map(t.entities["urls"], fn(u) -> u["expanded_url"] end)
end)
end
end
OTP
OTP2
• Large collection of libraries covering a wide range of use
cases
• Set of design principles encoded in behaviours
2
Open Telephony Platform - A marketing idea gone bad
Behaviours
• Specify callbacks that you implement to specialize your own
code
• Formalize common patterns
• Can create your own
• Four standard ones in Erlang
OTP GenServer
defmodule RedirectCounter.TwitterLinkStream do
use GenServer
def start_link do
GenServer.start_link __MODULE__, [], name: __MODULE__
end
def init(_) do
GenServer.cast __MODULE__, :stream
{ :ok, nil }
end
def handle_cast(:stream, state) do
spawn_link fn ->
RedirectCounter.Twitter.links
|> Enum.each(&RedirectCounter.CounterSupervisor.process/1)
end
{ :noreply, state }
end
end
defmodule RedirectCounter.Count do
use GenServer
def start_link do
GenServer.start_link __MODULE__, [], name: __MODULE__
end
def log(redirect_count) do
GenServer.cast __MODULE__, { :redirect_count, redirect_count }
end
def get do
GenServer.call __MODULE__, :get
end
def init(_) do
{ :ok, %{} }
end
def handle_cast({:redirect_count, redirect_count}, state) do
state = Map.update(state, redirect_count, 1, fn(n) -> n + 1 end)
{ :noreply, state }
end
def handle_call(:get, _from, state) do
{ :reply, state, state }
end
end
def start_link do
GenServer.start_link __MODULE__, [], name: __MODULE__
end
def log(redirect_count) do
GenServer.cast __MODULE__, { :redirect_count, redirect_count }
end
def get do
GenServer.call __MODULE__, :get
end
def init(_) do
{ :ok, %{} }
end
def handle_cast({:redirect_count, redirect_count}, state) do
state = Map.update(state, redirect_count, 1, fn(n) -> n + 1 end)
{ :noreply, state }
end
def handle_call(:get, _from, state) do
{ :reply, state, state }
end
iex(1)> alias RedirectCounter.Count
nil
iex(2)> Count.start_link
{:ok, #PID<0.91.0>}
iex(3)> Count.log(1)
:ok
iex(4)> Count.log(1)
:ok
iex(5)> Count.log(1)
:ok
iex(6)> Count.log(2)
:ok
iex(7)> Count.log(3)
:ok
iex(8)> Count.get
%{1 => 3, 2 => 1, 3 => 1}
Call vs Cast
Cast
• Asynchronous
• fire & forget
• More decoupled
• Less control over when things happen
Call
• Synchronous
• More coupled
• More control over order of events
OTP Supervisors
Supervisors
• Don't do any processing
• Start and restart workers and other supervisors
• Prevent errors taking the entire application down
• Shutdown system in a controlled manor
Supervision Trees
defmodule RedirectCounter.Supervisor do
use Supervisor
def start_link do
Supervisor.start_link(__MODULE__, [])
end
def init(_) do
children = [
worker(RedirectCounter.Count, []),
worker(RedirectCounter.ConsoleOutput, []),
supervisor(RedirectCounter.CounterSupervisor, []),
worker(RedirectCounter.TwitterLinkStream, [])
]
supervise(children, strategy: :one_for_one)
end
end
defmodule RedirectCounter.CounterSupervisor do
use Supervisor
def start_link do
Supervisor.start_link __MODULE__, [], name: __MODULE__
end
def process(url) do
{:ok, pid} = Supervisor.start_child(__MODULE__, [url])
GenServer.cast(pid, :count)
end
def init(_) do
children = [
worker(RedirectCounter.URLRedirectCounter, [],
restart: :temporary, shutdown: :brutal_kill)
]
supervise(children, strategy: :simple_one_for_one)
end
end
defmodule RedirectCounter.URLRedirectCounter do
use GenServer
def start_link(url) do
GenServer.start_link(__MODULE__, url)
end
def init(url) do
{ :ok, url }
end
def handle_cast(:count, url) do
redirect_count = RedirectCounter.URL.count_redirects(url)
RedirectCounter.Count.log(redirect_count)
{ :stop, :normal, url }
end
end
Supervision Strategies
• one_for_one
• simple_one_for_one
• rest_for_one
• one_for_all
Restart options
• permanent
• temporary
• transient
Error Kernel
Good Erlang design begins with identifying the error kernel of
the system: What part must not fail or it will bring down the whole
system?
— Jesper Louis Anderson
Error Kernel
Whenever the kernel is about to do an operation which is
dangerous and might crash, you "outsource" that computation to
another process, a dumb slave worker. If he crashes and is killed,
nothing really bad has happened - since the kernel keeps going.
— Jesper Louis Anderson
Agent
# Plain GenServer
defmodule RedirectCounter.Count do
use GenServer
def start_link do
GenServer.start_link __MODULE__, [], name: __MODULE__
end
def log(redirect_count) do
GenServer.cast __MODULE__, { :redirect_count, redirect_count }
end
def get do
GenServer.call __MODULE__, :get
end
def init(_) do
{ :ok, %{} }
end
def handle_cast({:redirect_count, redirect_count}, state) do
state = Map.update(state, redirect_count, 1, fn(n) -> n + 1 end)
{ :noreply, state }
end
def handle_call(:get, _from, state) do
{ :reply, state, state }
end
end
# Elixir Agent
defmodule RedirectCounter.Count do
def start_link do
Agent.start_link(fn -> %{} end, name: __MODULE__)
end
def log(redirect_count) do
Agent.update(__MODULE__,
&Map.update(&1, redirect_count, 1, fn(n) -> n + 1 end))
end
def get do
Agent.get(__MODULE__, fn(map) -> map end)
end
end
Task and
Task.Supervisor
Simple Example
task = Task.async(fn -> do_some_work() end)
res = do_some_other_work()
res + Task.await(task)
# Main Supervisor - Before
defmodule RedirectCounter.Supervisor do
use Supervisor
def start_link do
Supervisor.start_link(__MODULE__, [])
end
def init(_) do
children = [
worker(RedirectCounter.Count, []),
worker(RedirectCounter.ConsoleOutput, []),
supervisor(RedirectCounter.CounterSupervisor, []),
worker(RedirectCounter.TwitterLinkStream, [])
]
supervise(children, strategy: :one_for_one)
end
end
# Main Supervisor - After
defmodule RedirectCounter.Supervisor do
use Supervisor
def start_link do
Supervisor.start_link(__MODULE__, [])
end
def init(_) do
children = [
worker(RedirectCounter.Count, []),
worker(RedirectCounter.ConsoleOutput, []),
supervisor(Task.Supervisor, [[name: :counter_supervisor]]),
worker(Task, [RedirectCounter.Twitter, :process, [&RedirectCounter.URL.process/1]])
]
supervise(children, strategy: :one_for_one)
end
end
# Previous RedirectCounter.Twitter
defmodule RedirectCounter.Twitter do
def configure do
# ... boring setup ...
end
def links do
configure
ExTwitter.stream_filter(track: "link")
|> Stream.reject(fn(t) -> t.entities["urls"] == [] end)
|> Stream.flat_map(fn(t) ->
Enum.map(t.entities["urls"], fn(u) -> u["expanded_url"] end)
end)
end
end
# Updated RedirectCounter.Twitter
defmodule RedirectCounter.Twitter do
def process(fun) do
links |> Enum.each(fun)
end
# ...
end
# Previous RedirectCounter.URL
defmodule RedirectCounter.URL do
@max_redirects 10
def count_redirects(url) do
{ :ok, response } = HTTPoison.head(url)
do_count(response.status_code, response.headers["Location"], 0)
end
defp do_count(_status_code, _url, @max_redirects), do: raise "To many redirects"
defp do_count(status_code, url, redirect_count) when status_code in [301, 302, 307] do
{ :ok, response } = HTTPoison.head(url)
do_count(response.status_code, response.headers["Location"], redirect_count + 1)
end
defp do_count(_status_code, _url, redirect_count) do
redirect_count
end
end
# Updated RedirectCounter.URL
defmodule RedirectCounter.URL do
def process(url) do
Task.Supervisor.start_child(:counter_supervisor, __MODULE__, :count_redirects, [url])
end
def count_redirects(url) do
{ :ok, response } = HTTPoison.head(url)
redirect_count = do_count(response.status_code, response.headers["Location"], 0)
RedirectCounter.Count.log(redirect_count)
end
# ...
end
What I haven't covered
• gen_event and gen_fsm
• Applications (in Erlang terminology)
• Upgrades and hot code reloading
• Debugging, monitoring, and logging
• The other parts of OTP (ssh, asn.1, ...)
• ets / mnesia (built in "NoSQL" databases)
Interesting Elixir projects
• Plug: Rack/WSGI like layer for Elixir
• Phoenix: Batteries included web/websockets framework
• Ewebmachine: Generates HTTP responses based on HTTP
decision tree
• Ecto: LINQ inspired database abstraction layer
ElixirConf.eu
23rd - 24th April 2015
Krakow, Poland
http://www.elixirconf.eu
Thanks!
I hope I've interested you in Elixir and Erlang/OTP
• http://elixir-lang.org
• Progamming Elixir - Pragmatic Programmers
• Elixir in Action - Manning
• Erlang and OTP in Action - Manning
• http://www.erlang-in-anger.com/

More Related Content

What's hot

Elixir and Phoenix for Rubyists
Elixir and Phoenix for RubyistsElixir and Phoenix for Rubyists
Elixir and Phoenix for RubyistsBrooklyn Zelenka
 
Ida python intro
Ida python introIda python intro
Ida python intro小静 安
 
Creating Lazy stream in CSharp
Creating Lazy stream in CSharpCreating Lazy stream in CSharp
Creating Lazy stream in CSharpDhaval Dalal
 
Damien seguy php 5.6
Damien seguy php 5.6Damien seguy php 5.6
Damien seguy php 5.6Damien Seguy
 
Tame cloud complexity with F# powered DSLs (build stuff)
Tame cloud complexity with F# powered DSLs (build stuff)Tame cloud complexity with F# powered DSLs (build stuff)
Tame cloud complexity with F# powered DSLs (build stuff)Yan Cui
 
Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)Damien Seguy
 
Zephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensionsZephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensionsMark Baker
 
Python Programming Essentials - M19 - Namespaces, Global Variables and Docstr...
Python Programming Essentials - M19 - Namespaces, Global Variables and Docstr...Python Programming Essentials - M19 - Namespaces, Global Variables and Docstr...
Python Programming Essentials - M19 - Namespaces, Global Variables and Docstr...P3 InfoTech Solutions Pvt. Ltd.
 
Effective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good PracticesEffective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good PracticesNaresha K
 
جلسه پنجم پایتون برای هکر های قانونی دوره مقدماتی پاییز ۹۲- ارائه ۱
جلسه پنجم پایتون برای هکر های قانونی دوره مقدماتی پاییز ۹۲- ارائه ۱جلسه پنجم پایتون برای هکر های قانونی دوره مقدماتی پاییز ۹۲- ارائه ۱
جلسه پنجم پایتون برای هکر های قانونی دوره مقدماتی پاییز ۹۲- ارائه ۱Mohammad Reza Kamalifard
 
PowerShell 101
PowerShell 101PowerShell 101
PowerShell 101Thomas Lee
 
React Native Evening
React Native EveningReact Native Evening
React Native EveningTroy Miles
 
Php pattern matching
Php pattern matchingPhp pattern matching
Php pattern matchingJIGAR MAKHIJA
 
Introduction To Power Shell
Introduction To Power ShellIntroduction To Power Shell
Introduction To Power ShellIvan Suhinin
 
Php server variables
Php server variablesPhp server variables
Php server variablesJIGAR MAKHIJA
 
What To Expect From PHP7
What To Expect From PHP7What To Expect From PHP7
What To Expect From PHP7Codemotion
 

What's hot (20)

Elixir for rubysts
Elixir for rubystsElixir for rubysts
Elixir for rubysts
 
Elixir and Phoenix for Rubyists
Elixir and Phoenix for RubyistsElixir and Phoenix for Rubyists
Elixir and Phoenix for Rubyists
 
Ida python intro
Ida python introIda python intro
Ida python intro
 
Creating Lazy stream in CSharp
Creating Lazy stream in CSharpCreating Lazy stream in CSharp
Creating Lazy stream in CSharp
 
Damien seguy php 5.6
Damien seguy php 5.6Damien seguy php 5.6
Damien seguy php 5.6
 
Tame cloud complexity with F# powered DSLs (build stuff)
Tame cloud complexity with F# powered DSLs (build stuff)Tame cloud complexity with F# powered DSLs (build stuff)
Tame cloud complexity with F# powered DSLs (build stuff)
 
Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)Preparing for the next PHP version (5.6)
Preparing for the next PHP version (5.6)
 
Zephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensionsZephir - A Wind of Change for writing PHP extensions
Zephir - A Wind of Change for writing PHP extensions
 
Python Programming Essentials - M19 - Namespaces, Global Variables and Docstr...
Python Programming Essentials - M19 - Namespaces, Global Variables and Docstr...Python Programming Essentials - M19 - Namespaces, Global Variables and Docstr...
Python Programming Essentials - M19 - Namespaces, Global Variables and Docstr...
 
Effective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good PracticesEffective Java with Groovy - How Language Influences Adoption of Good Practices
Effective Java with Groovy - How Language Influences Adoption of Good Practices
 
Elixir introduction
Elixir introductionElixir introduction
Elixir introduction
 
جلسه پنجم پایتون برای هکر های قانونی دوره مقدماتی پاییز ۹۲- ارائه ۱
جلسه پنجم پایتون برای هکر های قانونی دوره مقدماتی پاییز ۹۲- ارائه ۱جلسه پنجم پایتون برای هکر های قانونی دوره مقدماتی پاییز ۹۲- ارائه ۱
جلسه پنجم پایتون برای هکر های قانونی دوره مقدماتی پاییز ۹۲- ارائه ۱
 
PowerShell 101
PowerShell 101PowerShell 101
PowerShell 101
 
React Native Evening
React Native EveningReact Native Evening
React Native Evening
 
Perl Basics with Examples
Perl Basics with ExamplesPerl Basics with Examples
Perl Basics with Examples
 
Intro to Perl and Bioperl
Intro to Perl and BioperlIntro to Perl and Bioperl
Intro to Perl and Bioperl
 
Php pattern matching
Php pattern matchingPhp pattern matching
Php pattern matching
 
Introduction To Power Shell
Introduction To Power ShellIntroduction To Power Shell
Introduction To Power Shell
 
Php server variables
Php server variablesPhp server variables
Php server variables
 
What To Expect From PHP7
What To Expect From PHP7What To Expect From PHP7
What To Expect From PHP7
 

Similar to Introducing Elixir and OTP at the Erlang BASH

Introduction to Elixir
Introduction to ElixirIntroduction to Elixir
Introduction to ElixirDiacode
 
Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of Elixir
Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of ElixirYurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of Elixir
Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of ElixirElixir Club
 
Elixir formatter Internals
Elixir formatter InternalsElixir formatter Internals
Elixir formatter InternalsPedro Medeiros
 
Elixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicitElixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicitTobias Pfeiffer
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring ClojurescriptLuke Donnet
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patternsTomasz Kowal
 
Combinators, DSLs, HTML and F#
Combinators, DSLs, HTML and F#Combinators, DSLs, HTML and F#
Combinators, DSLs, HTML and F#Robert Pickering
 
Introduction to Elixir
Introduction to ElixirIntroduction to Elixir
Introduction to Elixirbrien_wankel
 
Course 102: Lecture 8: Composite Commands
Course 102: Lecture 8: Composite Commands Course 102: Lecture 8: Composite Commands
Course 102: Lecture 8: Composite Commands Ahmed El-Arabawy
 
Phoenix demysitify, with fun
Phoenix demysitify, with funPhoenix demysitify, with fun
Phoenix demysitify, with funTai An Su
 
Blocks by Lachs Cox
Blocks by Lachs CoxBlocks by Lachs Cox
Blocks by Lachs Coxlachie
 
Advanced Internationalization with Rails
Advanced Internationalization with RailsAdvanced Internationalization with Rails
Advanced Internationalization with RailsClinton Dreisbach
 

Similar to Introducing Elixir and OTP at the Erlang BASH (20)

Introduction to Elixir
Introduction to ElixirIntroduction to Elixir
Introduction to Elixir
 
Elixir
ElixirElixir
Elixir
 
Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of Elixir
Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of ElixirYurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of Elixir
Yurii Bodarev - OTP, Phoenix & Ecto: Three Pillars of Elixir
 
Elixir formatter Internals
Elixir formatter InternalsElixir formatter Internals
Elixir formatter Internals
 
Elixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicitElixir & Phoenix - fast, concurrent and explicit
Elixir & Phoenix - fast, concurrent and explicit
 
Exploring Clojurescript
Exploring ClojurescriptExploring Clojurescript
Exploring Clojurescript
 
Refactoring
RefactoringRefactoring
Refactoring
 
Very basic functional design patterns
Very basic functional design patternsVery basic functional design patterns
Very basic functional design patterns
 
C Tutorials
C TutorialsC Tutorials
C Tutorials
 
Combinators, DSLs, HTML and F#
Combinators, DSLs, HTML and F#Combinators, DSLs, HTML and F#
Combinators, DSLs, HTML and F#
 
Introduction to Elixir
Introduction to ElixirIntroduction to Elixir
Introduction to Elixir
 
Erlang, an overview
Erlang, an overviewErlang, an overview
Erlang, an overview
 
Course 102: Lecture 8: Composite Commands
Course 102: Lecture 8: Composite Commands Course 102: Lecture 8: Composite Commands
Course 102: Lecture 8: Composite Commands
 
Phoenix demysitify, with fun
Phoenix demysitify, with funPhoenix demysitify, with fun
Phoenix demysitify, with fun
 
Elixir cheatsheet
Elixir cheatsheetElixir cheatsheet
Elixir cheatsheet
 
Clojure intro
Clojure introClojure intro
Clojure intro
 
Migrating legacy data
Migrating legacy dataMigrating legacy data
Migrating legacy data
 
Erlang session1
Erlang session1Erlang session1
Erlang session1
 
Blocks by Lachs Cox
Blocks by Lachs CoxBlocks by Lachs Cox
Blocks by Lachs Cox
 
Advanced Internationalization with Rails
Advanced Internationalization with RailsAdvanced Internationalization with Rails
Advanced Internationalization with Rails
 

Recently uploaded

What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...Technogeeks
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
VK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web DevelopmentVK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web Developmentvyaparkranti
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfAlina Yurenko
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identityteam-WIBU
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Cizo Technology Services
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfDrew Moseley
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Hr365.us smith
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxAndreas Kunz
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceBrainSell Technologies
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...OnePlan Solutions
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Mater
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringHironori Washizaki
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 

Recently uploaded (20)

What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
VK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web DevelopmentVK Business Profile - provides IT solutions and Web Development
VK Business Profile - provides IT solutions and Web Development
 
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdfGOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
GOING AOT WITH GRAALVM – DEVOXX GREECE.pdf
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identity
 
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
Global Identity Enrolment and Verification Pro Solution - Cizo Technology Ser...
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdf
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)Recruitment Management Software Benefits (Infographic)
Recruitment Management Software Benefits (Infographic)
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
 
CRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. SalesforceCRM Contender Series: HubSpot vs. Salesforce
CRM Contender Series: HubSpot vs. Salesforce
 
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)Ahmed Motair CV April 2024 (Senior SW Developer)
Ahmed Motair CV April 2024 (Senior SW Developer)
 
Machine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their EngineeringMachine Learning Software Engineering Patterns and Their Engineering
Machine Learning Software Engineering Patterns and Their Engineering
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 

Introducing Elixir and OTP at the Erlang BASH

  • 1. Elixir and OTP Chris McGrath @chrismcg chris@chrismcg.com
  • 3. Elixir Elixir is a dynamic, functional language designed for building scalable and maintainable applications. Elixir leverages the Erlang VM, known for running low-latency, distributed and fault-tolerant systems, while also being successfully used in web development and the embedded software domain. — http://www.elixir-lang.org
  • 4. What Elixir is NOT • Some sort of CoffeeScript for Erlang • A port of Ruby to Erlang • Just Erlang with nicer syntax
  • 5. Some example code defmodule RedirectCounter.URL do @max_redirects 10 def count_redirects(url) do { :ok, response } = HTTPoison.head(url) do_count(response.status_code, response.headers["Location"], 0) end defp do_count(_status_code, _url, @max_redirects), do: raise "To many redirects" defp do_count(status_code, url, redirect_count) when status_code in [301, 302, 307] do { :ok, response } = HTTPoison.head(url) do_count(response.status_code, response.headers["Location"], redirect_count + 1) end defp do_count(_status_code, _url, redirect_count), do: redirect_count end
  • 8. "Boss" Reasons • Our systems are becoming more and more parallel and the primitives provided by most languages are quite low level • Runs on top of the Erlang runtime, famous for amazing uptimes and fault tolerance • Powerful macro system for creating DSLs and reducing boilerplate • OTP library and architecture makes it easier to create fault tolerant systems
  • 9. What's Elixir useful for? • Network related tasks (from plain sockets to web servers and frameworks) • Writing reliable, distributed, and highly available software • MMO backends (not frontends!) • Using all the cores • (AKA Things Erlang Is Good For)
  • 10. What Elixir adds to Erlang • Modules for namespacing • Macros • A focus on tooling • Streaming
  • 11. What Elixir adds to Erlang • Much nicer string handling • Consistent function parameters • Clearer organization of standard library • Variable rebinding • Less fiddly syntax
  • 12. Language Highlights • Mix project management tool • First class documentation and doctests • Toll free calling of Erlang functions • Macros • Pipeline Operator • Protocols
  • 13. Mix • Generates and manages projects • Somewhat similar to leiningen • Like Make/Rake it can compile and runs tests • Like Bundler it allows dependencies to be specified • Like Rails or Bundler it can generate new project skeletons • Full integration with Erlang, Rebar, and hex.pm
  • 14. IEx - Interactive Elixir REPL % iex iex(1)> x = 1 + 2 3 iex(2)> x = 4 4 iex(3)> IO.puts "Hello World" Hello World :ok
  • 15. Documentation & Doctests defmodule ShowDoctest do @moduledoc """ This module shows off an example of a doctest """ @doc """ Adds it's inputs together iex> ShowDoctest.add(1, 1) 2 """ def add(a, b) do a - b end end
  • 16. defmodule ShowDoctestTest do use ExUnit.Case, async: true doctest ShowDoctest end % mix test 1) test doc at ShowDoctest.add/2 (1) (ShowDoctestTest) test/show_doctest_test.exs:3 Doctest failed code: ShowDoctest.add(1, 1) === 2 lhs: 0 stacktrace: lib/show_doctest.ex:12: ShowDoctest (module)
  • 17. IEx Doc integration % iex -S mix iex(1)> h ShowDoctest ShowDoctest This module shows off an example of a doctest iex(2)> h ShowDoctest.add def add(a, b) Adds it's inputs together
  • 18. Toll free calling into erlang You can use any available Erlang library in your Elixir project % erl Eshell V6.3 (abort with ^G) 1> os:timestamp(). {1422,119363,162867} % iex iex(1)> :os.timestamp {1422, 119376, 391592}
  • 19. Macros Lisps traditionally empowered developers because you can eliminate anything that's tedious through macros, and that power is really what people keep going back for — Rich Hickey
  • 20. Macro Example test "some sums" do assert 1 + 1 == 3 end 1) test some math (TestProjectTest) ** (ExUnit.ExpectationError) expected: 2 to be equal to (==): 3 at test/test_project_test.exs:5
  • 21. Macro Example iex(1)> quote do: 1 + 1 == 3 {:==, [context: Elixir, import: Kernel], [{:+, [context: Elixir, import: Kernel], [1, 1]}, 3]} defmacro assert({ :==, _, [l, r]}) do # ... end defmacro assert({ :=~, _, [l, r]}) do # ... end
  • 22. Pipelines people = DB.find_customers orders = Orders.for_customers(people) tax = sales_tax(orders, 2013) filing = prepare_filing(tax)
  • 23. Pipelines filing = DB.find_customers |> Orders.for_customers |> sales_tax(2013) |> prepare_filing
  • 24. Pipelines # rewritten to... filing = prepare_filing( sales_tax( Orders.for_customers(DB.find_customers), 2013 ))
  • 25. Protocols • Let you have polymorphism in Elixir • Inspired heavily by Clojure • Can define implementation of built in protocols for your own types
  • 26. Protocols: Definition1 defprotocol Blank do @doc "Returns true if data is considered blank/empty" def blank?(data) end 1 Sorry, the syntax highlighter doesn't know about protocols yet
  • 27. Protocols: Implementation1 # Integers are never blank defimpl Blank, for: Integer do def blank?(_), do: false end # Just empty list is blank defimpl Blank, for: List do def blank?([]), do: true def blank?(_), do: false end #... 1 Sorry, the syntax highlighter doesn't know about protocols yet
  • 28. Protocols: Calling iex> Blank.blank?(0) false iex> Blank.blank?([]) true iex> Blank.blank?([1, 2, 3]) false
  • 29. Enumerable iex(1)> Enum.map([1, 2, 3], fn(x) -> x * x end) [1, 4, 9] iex(2)> Enum.map([1, 2, 3], &(&1 * &1)) [1, 4, 9]
  • 30. Enumerable iex(1)> stream = Stream.map([1, 2, 3], &(&1 * &1)) #Stream<[enum: [1, 2, 3], funs: [#Function<45.29647706/1 in Stream.map/2>]]> iex(2)> stream = Stream.map(stream, &Integer.to_string/1) #Stream<[enum: [1, 2, 3], funs: [#Function<45.29647706/1 in Stream.map/2>, #Function<45.29647706/1 in Stream.map/2>]]> iex(3)> Enum.to_list(stream) ["1", "4", "9"]
  • 31. # More example code defmodule RedirectCounter.Twitter do def configure do # ... boring setup ... end def links do configure ExTwitter.stream_filter(track: "link") |> Stream.reject(fn(t) -> t.entities["urls"] == [] end) |> Stream.flat_map(fn(t) -> Enum.map(t.entities["urls"], fn(u) -> u["expanded_url"] end) end) end end
  • 32. OTP
  • 33. OTP2 • Large collection of libraries covering a wide range of use cases • Set of design principles encoded in behaviours 2 Open Telephony Platform - A marketing idea gone bad
  • 34. Behaviours • Specify callbacks that you implement to specialize your own code • Formalize common patterns • Can create your own • Four standard ones in Erlang
  • 36. defmodule RedirectCounter.TwitterLinkStream do use GenServer def start_link do GenServer.start_link __MODULE__, [], name: __MODULE__ end def init(_) do GenServer.cast __MODULE__, :stream { :ok, nil } end def handle_cast(:stream, state) do spawn_link fn -> RedirectCounter.Twitter.links |> Enum.each(&RedirectCounter.CounterSupervisor.process/1) end { :noreply, state } end end
  • 37. defmodule RedirectCounter.Count do use GenServer def start_link do GenServer.start_link __MODULE__, [], name: __MODULE__ end def log(redirect_count) do GenServer.cast __MODULE__, { :redirect_count, redirect_count } end def get do GenServer.call __MODULE__, :get end def init(_) do { :ok, %{} } end def handle_cast({:redirect_count, redirect_count}, state) do state = Map.update(state, redirect_count, 1, fn(n) -> n + 1 end) { :noreply, state } end def handle_call(:get, _from, state) do { :reply, state, state } end end
  • 38. def start_link do GenServer.start_link __MODULE__, [], name: __MODULE__ end def log(redirect_count) do GenServer.cast __MODULE__, { :redirect_count, redirect_count } end def get do GenServer.call __MODULE__, :get end
  • 39. def init(_) do { :ok, %{} } end def handle_cast({:redirect_count, redirect_count}, state) do state = Map.update(state, redirect_count, 1, fn(n) -> n + 1 end) { :noreply, state } end def handle_call(:get, _from, state) do { :reply, state, state } end
  • 40. iex(1)> alias RedirectCounter.Count nil iex(2)> Count.start_link {:ok, #PID<0.91.0>} iex(3)> Count.log(1) :ok iex(4)> Count.log(1) :ok iex(5)> Count.log(1) :ok iex(6)> Count.log(2) :ok iex(7)> Count.log(3) :ok iex(8)> Count.get %{1 => 3, 2 => 1, 3 => 1}
  • 42. Cast • Asynchronous • fire & forget • More decoupled • Less control over when things happen
  • 43. Call • Synchronous • More coupled • More control over order of events
  • 45. Supervisors • Don't do any processing • Start and restart workers and other supervisors • Prevent errors taking the entire application down • Shutdown system in a controlled manor
  • 47. defmodule RedirectCounter.Supervisor do use Supervisor def start_link do Supervisor.start_link(__MODULE__, []) end def init(_) do children = [ worker(RedirectCounter.Count, []), worker(RedirectCounter.ConsoleOutput, []), supervisor(RedirectCounter.CounterSupervisor, []), worker(RedirectCounter.TwitterLinkStream, []) ] supervise(children, strategy: :one_for_one) end end
  • 48. defmodule RedirectCounter.CounterSupervisor do use Supervisor def start_link do Supervisor.start_link __MODULE__, [], name: __MODULE__ end def process(url) do {:ok, pid} = Supervisor.start_child(__MODULE__, [url]) GenServer.cast(pid, :count) end def init(_) do children = [ worker(RedirectCounter.URLRedirectCounter, [], restart: :temporary, shutdown: :brutal_kill) ] supervise(children, strategy: :simple_one_for_one) end end
  • 49. defmodule RedirectCounter.URLRedirectCounter do use GenServer def start_link(url) do GenServer.start_link(__MODULE__, url) end def init(url) do { :ok, url } end def handle_cast(:count, url) do redirect_count = RedirectCounter.URL.count_redirects(url) RedirectCounter.Count.log(redirect_count) { :stop, :normal, url } end end
  • 50. Supervision Strategies • one_for_one • simple_one_for_one • rest_for_one • one_for_all
  • 51. Restart options • permanent • temporary • transient
  • 52. Error Kernel Good Erlang design begins with identifying the error kernel of the system: What part must not fail or it will bring down the whole system? — Jesper Louis Anderson
  • 53. Error Kernel Whenever the kernel is about to do an operation which is dangerous and might crash, you "outsource" that computation to another process, a dumb slave worker. If he crashes and is killed, nothing really bad has happened - since the kernel keeps going. — Jesper Louis Anderson
  • 54. Agent
  • 55. # Plain GenServer defmodule RedirectCounter.Count do use GenServer def start_link do GenServer.start_link __MODULE__, [], name: __MODULE__ end def log(redirect_count) do GenServer.cast __MODULE__, { :redirect_count, redirect_count } end def get do GenServer.call __MODULE__, :get end def init(_) do { :ok, %{} } end def handle_cast({:redirect_count, redirect_count}, state) do state = Map.update(state, redirect_count, 1, fn(n) -> n + 1 end) { :noreply, state } end def handle_call(:get, _from, state) do { :reply, state, state } end end
  • 56. # Elixir Agent defmodule RedirectCounter.Count do def start_link do Agent.start_link(fn -> %{} end, name: __MODULE__) end def log(redirect_count) do Agent.update(__MODULE__, &Map.update(&1, redirect_count, 1, fn(n) -> n + 1 end)) end def get do Agent.get(__MODULE__, fn(map) -> map end) end end
  • 58. Simple Example task = Task.async(fn -> do_some_work() end) res = do_some_other_work() res + Task.await(task)
  • 59. # Main Supervisor - Before defmodule RedirectCounter.Supervisor do use Supervisor def start_link do Supervisor.start_link(__MODULE__, []) end def init(_) do children = [ worker(RedirectCounter.Count, []), worker(RedirectCounter.ConsoleOutput, []), supervisor(RedirectCounter.CounterSupervisor, []), worker(RedirectCounter.TwitterLinkStream, []) ] supervise(children, strategy: :one_for_one) end end
  • 60. # Main Supervisor - After defmodule RedirectCounter.Supervisor do use Supervisor def start_link do Supervisor.start_link(__MODULE__, []) end def init(_) do children = [ worker(RedirectCounter.Count, []), worker(RedirectCounter.ConsoleOutput, []), supervisor(Task.Supervisor, [[name: :counter_supervisor]]), worker(Task, [RedirectCounter.Twitter, :process, [&RedirectCounter.URL.process/1]]) ] supervise(children, strategy: :one_for_one) end end
  • 61. # Previous RedirectCounter.Twitter defmodule RedirectCounter.Twitter do def configure do # ... boring setup ... end def links do configure ExTwitter.stream_filter(track: "link") |> Stream.reject(fn(t) -> t.entities["urls"] == [] end) |> Stream.flat_map(fn(t) -> Enum.map(t.entities["urls"], fn(u) -> u["expanded_url"] end) end) end end
  • 62. # Updated RedirectCounter.Twitter defmodule RedirectCounter.Twitter do def process(fun) do links |> Enum.each(fun) end # ... end
  • 63. # Previous RedirectCounter.URL defmodule RedirectCounter.URL do @max_redirects 10 def count_redirects(url) do { :ok, response } = HTTPoison.head(url) do_count(response.status_code, response.headers["Location"], 0) end defp do_count(_status_code, _url, @max_redirects), do: raise "To many redirects" defp do_count(status_code, url, redirect_count) when status_code in [301, 302, 307] do { :ok, response } = HTTPoison.head(url) do_count(response.status_code, response.headers["Location"], redirect_count + 1) end defp do_count(_status_code, _url, redirect_count) do redirect_count end end
  • 64. # Updated RedirectCounter.URL defmodule RedirectCounter.URL do def process(url) do Task.Supervisor.start_child(:counter_supervisor, __MODULE__, :count_redirects, [url]) end def count_redirects(url) do { :ok, response } = HTTPoison.head(url) redirect_count = do_count(response.status_code, response.headers["Location"], 0) RedirectCounter.Count.log(redirect_count) end # ... end
  • 65. What I haven't covered • gen_event and gen_fsm • Applications (in Erlang terminology) • Upgrades and hot code reloading • Debugging, monitoring, and logging • The other parts of OTP (ssh, asn.1, ...) • ets / mnesia (built in "NoSQL" databases)
  • 66. Interesting Elixir projects • Plug: Rack/WSGI like layer for Elixir • Phoenix: Batteries included web/websockets framework • Ewebmachine: Generates HTTP responses based on HTTP decision tree • Ecto: LINQ inspired database abstraction layer
  • 67. ElixirConf.eu 23rd - 24th April 2015 Krakow, Poland http://www.elixirconf.eu
  • 68. Thanks! I hope I've interested you in Elixir and Erlang/OTP • http://elixir-lang.org • Progamming Elixir - Pragmatic Programmers • Elixir in Action - Manning • Erlang and OTP in Action - Manning • http://www.erlang-in-anger.com/