I Code Elixir
And So Can YOU!
I'm not even going to pretend to be objective, but I will try to avoid hyperbole
FANBOY/KOOL-AID ALERT
What is 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.
Why Learn Elixir?
Haven't we invented all the languages?
Why Learn Elixir?
- Not Elixir, but Erlang
- FB bought for $17Bn w/ 600m+ active users
- >1Bn active users
- Millions of connections per server
- Low 1000's of servers
- 50 engineers total at FB sale, ~15 on backend
- Had no Erlang expert experience, but picked it up
Why Learn Elixir?
- Very early adopters
- Replaced Rails news aggregation with Elixir
- 20 servers down to 2 (only need 2 for redundancy)
- Expanded use of Elixir to power all their notifications
- They're replacing all Rails apps over time as teams choose to switch
Why Learn Elixir?
- Trial microservice
- Implemented Java-based rate limiter service in Elixir
- Cut # servers in half
- Percentile latency: 50th 500µs, 90th 800µs, 99th: 120ms-250ms
- Old 99th latency: 300ms-1200ms
- Code went from 10kloc to 1kloc
Why Learn Elixir?
- Has Erlang's traits (low latency) because it has Erlang's semantics
- Removes syntax anxiety
- Focuses on developer happiness
- Good tooling
- Value simplicity and correctness over being easy
- No magic!
- Great community welcomes new members
What is 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.
Language Basics
Dynamic
- No static typing in compiler
- Pattern matching helps
- Static analysis is available via
dialyzer
- Types are strict
- Type system can be extended
iex> x = 1
1
iex> 1 = x
1
iex> [a, b, c] = [1, 2, 3]
[1, 2, 3]
iex>; a
1
iex> [head|tail] = [1,2,3]
[1, 2, 3]
iex> head
1
iex> tail
[2, 3]
iex - Interactive Shell
(not just REPL)
iex> 1 # integer
iex> 0x1F # integer
iex> 1.0 # float
iex> true # boolean
iex> :atom # atom / symbol
iex> "elixir" # string
iex> [1, 2, 3] # list
iex> {1, 2, 3} # tuple
iex> %{key: "value"} # map
Basic Types
iex> x = 1
1
iex> 1 = x
1
iex> [a, b, c] = [1, 2, 3]
[1, 2, 3]
iex> a
1
iex> [head|tail] = [1,2,3]
[1, 2, 3]
iex> head
1
iex> tail
[2, 3]
Pattern Matching
iex> scores = %{ "users" => [{:alice, 500},
{:bob, 250},
{:carol, 100}] }
...
iex> %{"users" => [{first, _score}|_]} = scores
...
iex> first
:alice
Pattern Matching
iex> add = fn (a, b) -> a + b end
#Function<12.52032458/2 in :erl_eval.expr/5>
iex> add.(3, 5)
8
iex> add = &(&1+&2)
#&:erlang.+/2
iex> add.(3, 5)
8
iex> abs = fn (a) when a < 0 -> -a
(a) -> a
end
iex> abs.(-3)
3
iex> abs.(3)
3
Functions
iex> cond do
...> 2 + 2 == 5 ->
...> "This will not be true"
...> 2 * 2 == 3 ->
...> "Nor this"
...> 1 + 1 == 2 ->
...> "But this will"
...> end
"But this will"
iex> if nil do
...> "This won't be seen"
...> else
...> "This will"
...> end
"This will"
Conditionals
case File.write("/path/to/file", content) do
:ok -> :ok
{:error, :enospc} ->
IO.puts("Out of space.")
{:error, :enospc}
{:error, reason} ->
IO.puts("""
Didn't write to file because: #{inspect reason}.
""")
{:error, reason}
end
Conditionals
Hard Mode
iex> defmodule Test do
def test(0) do
IO.puts "Blastoff"
end
def test(n) do
IO.puts "#{n}"
end
end
...
iex> Test.test(3)
3
2
1
Blastoff!
:ok
Modules
iex> defmodule Factorial do
def fac(1) do
1
end
def fac(n) when n > 1 do
n * fac(n - 1)
end
end
...
iex> Factorial.fac(5)
120
Modules
Language Basics
Functional
- Code lives as functions in modules
- Lambda functions also exist
- All data is immutable
- Emphasis on data transformation over collections and streams
iex> Enum.each([1,2,3], fn i -> IO.puts "Test #{i}" end)
Test 1
Test 2
Test 3
:ok
iex> Enum.filter([1,2,3], &Integer.is_odd?/2)
[1, 3]
iex> Enum.map([1,2,3], fn i ->
IO.puts "Test #{i*2}"
i * 2
end)
Test 2
Test 4
Test 6
[2, 4, 6]
Iterating
Boring thing you're always doing
iex> "Hello, world!" |> IO.puts
Hello, world!
:ok
iex> [1,2,3]
|> Enum.map(&(&1*3))
|> Enum.filter(&Integer.is_odd?/1)
# Expands to:
# Enum.filter(
# Enum.map([1,2,3], &(&1*3)),
# &Integer.is_odd?/1
# )
[3, 9]
Pipe Operator
Amazing unix-like thing
[1,2,3,4,5]
|> Enum.filter(&Integer.is_odd?(&1))
|> case do
[1,3,5] -> :correct
_ -> :incorrect
end
|> IO.inspect
# Will print: :correct
Pipe Operator
Amazing unix-like thing
Language Basics
Concurrent + Parallel
- Code runs in isolated processes (like OS processes)
- Processes are scheduled by the VM, 1 scheduler per core
- Processes have internal GC (no stop-the-world)
- Processes are lightweight, 2KB or so of memory
Language Basics
Concurrent + Parallel
- Processes communicate by sending messages (async)
- A standard library called OTP provides building blocks for making applications
Language Basics
Distributed
- Erlang VM (BEAM) can be connect to other instances over TCP or SSL
- You can message a process ID to another VM and send messages
- There are a few apps for making distributed applications
Language Basics
Fault-Tolerant
- Erlang/Elixir libraries are called "applications"
- If they need to store state, they start processes under a "supervisor"
- When processes fail they can optionally be restarted, or reports can be filed for later inspection
Language Basics
Fault-Tolerant
- "Let it crash", someone will restart
- Works with computers
- If you crash too much/too fast, the supervisor crashes
- Putting too much defensive code is a bad "code smell"
- Code assertively to crash early
What's it good for?
Basic Microservices
- A process is practically a nanoservice
- Applications form a backbone for microservices
- "Releases" form a way of packaging up groups of applications as a single distributable
What's it good for?
The Web
- Phoenix Framework is a first-class web framework
- Offers familiar vocabulary to Rails
- A separate library, ecto, provides DB interaction and is heavily inspired by MS's LINQ
- Development is very quick and easy
- Community is very active
What's in the Tooling
-
iex
is a full Elixir shell, you can remote into nodes and restart the shell without restarting the VM -
mix
is a task runner and hosts the compiler and toolset -
hex
is a package repository for everything http://hex.pm/ -
elixir
will run a plain elixir file
Tools
-
dialyzer
will type-check your code -
observer
will let you look at a running system live -
credo
will give you opinions on your code and let you come up with style documents to enforce code style -
ex_unit
unit testing framework, extremely parallel
What's it good for?
Embedded Platforms
- Nerves Project provides great development environment for embedded hardware
- Needs about 32MB RAM, 200MHz, 16MB storage
- Phoenix on RPi runs hundreds of requests per second baseline
What's it good for?
Embedded Platforms
- You run a build and get a firmware file that's a few tens of MB
- Mix will prompt you to burn on an SD card
- A mix of read-only filesystems with writeable filesystems for configuration and logging prevent SD card and flash corruption
What it's not good for
- Math: All integers are Bignums after Ericsson did a study on how much overflow bugs cost per year, so math is slow
- Systems programming: You're not going to write an OS in this or a browser
Questions?
Let's start up a demo VM
ElixirTalk-0.0.1
By asonge
ElixirTalk-0.0.1
- 361