July 20th 2016

ORGANIZERS

Charles King

@thebringking

Mike Groseclose

@mikrofusion

Omer Wazir

@thewazir

Chris Steinmeyer

@chrisfishwood

Introduction to Elixir

  • What is elixir?

  • What is Erlang/OTP?

  • What problems does it solve?

  • When should you use it?

  • Our favorite Parts

  • Resources for learning Elixir/OTP

Topics

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.”

Concurrency/Scalability

parent = self()

# Spawns an Elixir process (not an operating system one!)
spawn_link(fn ->
  send parent, {:msg, "hello world"}
end)

# Block until the message is received
receive do
  {:msg, contents} -> IO.puts contents
end

Immutability

# simple list
[iex(1)> organizers = [:charlie,:chris,:omer,:mike] 
[:charlie,:chris,:omer,:mike] 

# delete an item
[iex(2)> List.delete(organizers, :charlie)
[:chris, :omer, :mike]

Tooling

$ mix new my_app
$ cd my_app
$ mix test
.

Finished in 0.04 seconds (0.04s on load, 0.00s on tests)
1 tests, 0 failures



$ iex
Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)
iex> c "my_file.ex"        # Compiles a file
iex> t Enum                # Prints types defined in the module Enum
iex> h IEx.pry             # Prints the documentation for IEx pry functionality
iex> i "Hello, World"      # Prints information about the given data type

Metaprogramming

# Quoting
iex> quote do: sum(1, 2, 3)

# Elixir AST
{:sum, [], [1, 2, 3]}

# Unquoting
iex> number = 13
iex> Macro.to_string(quote do: 11 + number)
"11 + number"

iex> number = 13
iex> Macro.to_string(quote do: 11 + unquote(number))
"11 + 13"

What is Erlang/OTP

Any sufficiently complicated concurrent program in another language contains an ad hoc informally-specified bug-ridden slow implementation of half of Erlang"

Rober Virding

  • Erlang was built in 1986 to solve Ericsson's software problems

  • Erlang is a general-purpose programming language and runtime environment. Erlang has built-in support for concurrency, distribution and fault tolerance

  • Erlang runs on a VM called BEAM

OTP - Open Telecom Platform

  • Set of middleware, tools and libraries to help you write resilient code

📽🎞 Erlang: The Movie 📞☎️🍿

What problems does it solve?

Fast for Computers

Fast for Humans

Python

Ruby

JavaScript

C

C++

Elixir

Go

Rust

Java

Erlang

“Elixir is optimized for developer happiness” – via @mwoods79

Created by active Ruby contributor Jose Valim

When should you use it?

  • Having trouble scaling your Ruby application

  • To easily use more than one CPU core (shame on NodeJS)

  • Want to embrace functional programming, with friendly semantics

Our favorite parts

  • Charlie - Processes

  • Mike - Pattern Matching

  • Chris - Umbrella Projects

  • Omer - Streams & Flows

Processes - Charlie

"Processes are isolated from each other, run concurrent to one another and communicate via message passing"

"...not be confused with operating system processes. Processes in Elixir are extremely lightweight in terms of memory and CPU... ...not uncommon to have tens or even hundreds of thousands of processes running simultaneously."

iex> pid = spawn fn -> 1 + 2 end
#PID<0.44.0>
iex> Process.alive?(pid)
false

Processes - Contrived Example

Real world example

Elixir Supervisor 

Elixir Processes running NodeJS

http request

html

Streams & Flows - Omer

Streams are composable, lazy enumerables. Any enumerable that generates items one by one during enumeration is called a stream. A stream will not consume or output an item until a regular Enum asks.

In Elixir the Enum module is eager, always consuming an entire collection and often resulting in another collection. Piped enumerable operations create intermediary collections.

Enums Example

iex(1)> organizers = ["Charlie","Chris","Mike","Omer"]
iex(2)> Enum.with_index(organizers)
[{"Charlie", 0}, {"Chris", 1}, {"Mike", 2}, {"Omer", 3}]
iex(3)> organizers |>
...(3)> Enum.with |>
...(3)> Enum.each( fn(organizer, index) ->
...(3)>  IO.puts "#{index + 1}. #{organizer}"
...(3)> end)
1. Charlie
2. Chris
3. Mike
4. Omer

Using the Enum module creates intermediary collections

Streams Example

iex(1)> organizers = ["Charlie","Chris","Mike","Omer"]
iex(2)> Stream.with_index(organizers)
#Stream<[enum: ["Charlie", "Chris", "Mike", "Omer"], 
funs: [#Function<62.89908360/1 in Stream.with_index/2>]]>  
iex(3)> organizers |>
...(3)> Stream.with |>
...(3)> Enum.each( fn(organizer, index) ->
...(3)>  IO.puts "#{index + 1}. #{organizer}"
...(3)> end)
1. Charlie
2. Chris
3. Mike
4. Omer


def getWords(path) do
File.stream!(path)
	|> Stream.flat_map(&String.split(&1, " "))
    |> Enum.reduce(%{}, fn word, acc ->
        	Map.update(acc, word, 1,& &1 + 1)
     	end)
    |> Enum.to_list()
end

Using Stream.with_index creates a recipe of computation - nothing is evaluated until Enum.each is called

Concurrency with GenStage.Flow

GenStage.Flow executes computation stages in parallel

[file stream]  # Flow.from_enumerable/1 (producer)
    |    |
  [M1]  [M2]    # Flow.flat_map/2 (producer-consumer)
    |\  /|
    | \/ |
    |/ \ |
  [R1]  [R2]    # Flow.reduce/3 (consumer)

M1 & M2 stages receive lines and break them into words

M1 - ["roses", "are", "red"]
M2 - ["violets", "are", "blue"]


Words are consistently routed to R1 or R2 regardless of origin
R1 - ["roses", "are", "red", "are"]
R2 - ["violets", "blue"]


Results of reduced stages
R1 - %{"roses" => 1, "are" => 2, "red" => 1}
R2 - %{"violets" => 1, "blue" => 1}
def getWords(path) do
    File.stream!(path)
    |> Enum.flat_map(&String.split(&1, " "))
    |> Enum.reduce(%{}, fn word, acc ->
        Map.update(acc, word, 1,& &1 + 1)
    end)
    |> Enum.to_list()
end
def getWords(path) do
    File.stream!(path)
    |> Stream.flat_map(&String.split(&1, " "))
    |> Enum.reduce(%{}, fn word, acc ->
        Map.update(acc, word, 1,& &1 + 1)
    end)
    |> Enum.to_list()
end
alias Experimental.GenStage.Flow

def getWords(path) do
    File.stream!(path)
    |> Flow.from_enumerable()
    |> Flow.flat_map(&String.split(&1, " "))
    |> Flow.partition()
    |> Flow.reduce(fn -> %{} end, fn word, acc ->
        Map.update(acc, word, 1, & &1+ 1)
    end)
    |> Enum.to_list()
end

Word count performance in microseconds reading a 12 megabyte text file

Pattern Matching - Mike

=

the match operator

Basic Matching

1 = x because the left hand matches the right hand.

 

What happens if we try 2 = x ?

Basic Matching

The left hand side does not match the right hand side, so an error is thrown.

Pattern Matching Lists

OK, so how is this different from destructuring assignment?

Pattern Matching Lists

Left hand side can contain values 😱

Pattern Matching Lists

As we'd expect, a match error will occur when a match can't be made.

Pattern Matching Structs

Structs are extensions built on top of maps that provide compile-time checks and default values.

Pattern Matching Structs (Continued)

Let's match against a user struct based on the User.count matching 1

Control-flow Structures

case allows us to compare a value against many patterns until we find a matching one

Putting It All Together

Let's assume we have soft-deletable Users.

Let's find a User (if they are not deleted).

Putting It All Together

The wrong way.

Putting It All Together

Better.

Putting It All Together

👍

Umbrella Projects

☂️

What is an umbrella project?

A project that contains multiple applications.

What are the benefits of umbrella projects over traditional projects?

   Umbrella apps offer a cleaner code hierarchy and easier/cleaner tooling

Can utilize GenServer for process supervision

Like a monolith, but totally not!

Like microservices, but totally not!

Greater application flexibility

Resources for learning Elixir

Elixir Language website

Elixir School

Books

  • Programming Elixir 1.2 by Dave Thomas

  • Elixir in Action by Saša Jurić

  • Introducing Elixir by Simon St. Laurent, J. David Eisenberg

  • The Little Elixir and OTP Guidebook by Benjamin Tan Wei Hao

Erlang books (Great for learning OTP too)

  • Learn You Some Erlang for great good! by Frederic Trottier-Hebert

  • Introducing Erlang by Simon St. Laurent

  • Designing for Scalability with Erlang/OTP by  Francesco Cesarini, Steve Vinoski

Programming exercises

  • Exercism.io

  • Codewars.com

  • reddit.com/r/dailyprogrammer

  • Études for Elixir

  • cryptopals crypto challenges

Community

Useful articles, videos and repos

  • Elixir source code on Github

  • Erlang Solutions YouTube channel

  • Riak and Erlang/OTP - The Architecture of Open Source Applications http://www.aosabook.org/en/riak.html

  • For large OTP apps see RabbitMQ or Riak 

Elixir Introduction

By Charles King

Elixir Introduction

  • 908