2015 - L’année d’Elixir : Les raisons du
succès.
13 octobre 2015
Mickaël Rémond <mremond@process-one.net>
2015: L’année d’Elixir: Code,
écosystème et communauté
La communauté Elixir en effervescence
• En développement depuis 2011.
Le développement s’accélère depuis que le language est stable. Elixir 1.0
publié en septembre 2014, suivi de Elixir 1.1 en septembre 2015.
• Sortie du Framework de développement Web Phoenix en août 2015 en
version 1.0.
Elixir - 9 Jan 2011 - README first commit
Elixir - 10 Jan 2011 - Added basic lexer
Elixir - + de 4 ans après
1.0.0 1.1.0
8867 commits - 365 contributeurs
Elixir - + de 4 ans après
131k lignes de code
Le Framework Phoenix, le "Rails" d’Elixir ?
La communauté Elixir revitalise Erlang
• Une influence majeure sur la VM Erlang:
• Maps et optimisation des performances.
• Hex.pm
• Réflexion sur le langage
Elixir, l’explosion, la seconde jeunesse
d'Erlang
Une communauté active et décentralisée
• La participation aux
conférences Elixir est en
forte augmentation.
250 participants cette
année à la conférence
Elixir à Austin
• Des “meetups” dans le
monde entier
Publications
• 7 livres publiés ou en cours sur le sujet.
Les forces du langage: Ecosystème, influence
et communauté
• Des outils pensés dès la conception du langage pour la productivité:
• Mix
• Hex.pm
• exUnit
• Phoenix,
• exrm, …
• Un langage mêlant les influences:
• Influence d’Erlang (car construit sur la VM Erlang).
• Influence de Ruby et de Rails
• Influence de Lisp, C#, Python, Haskell, etc…
• Une communauté ouverte et accueillante. Les débutants sont accompagnés. Le
langage attire des développeurs auparavant rebuté par la syntaxe d’Erlang.
Cas d’usage modernes
• Elixir est bien adapté:
• aux systèmes de messaging en général:
• Exemples: ProcessOne / ejabberd.
• pour le développement Web, d’API et de “micro-services”, grâce au
framework Phoenix.
• Exemples: Plataformatec, Brightcove, Shopping Adventure
• au développement de DSL (Domain Specific Languages), grâce au
système de macros évolué d’Elixir,
• Les plates-formes transactionnelles de masse: Jeu vidéo, finance.
• Exemples: Undead Labs
• à l’informatique embarquée (Raspberry Pi, Beagle board).
• Exemples: Rose Point Navigation Systems.
• à la gestion de la masse de signaux produits par l’Internet of Things.
Les idées fortes d'Elixir
Les idées fortes d'Elixir
• Pattern matching
• Les fonctions transforment les données: Les "pipes" |>
• Meta-Programmation s’appuyant sur les macros.
• Extensibilité / Polymorphisme: Protocols.
• Shell puissant pour le debug et la gestion d’une plate-forme de production.
• Documentation dans le code accessible depuis la ligne de commande.
• “For Comprehension” / into.
• Performance et clustering natif.
• Compatibilité avec Erlang. Réutilise des années de travail sur la distribution et
le parallélisme et des centaines de milliers de ligne de code.
• Upgrade de code à chaud et release.
• Les patterns Erlang OTP: Supervisors, servers, etc
Pattern matching
• Le pattern matching permet d’écrire un code plus expressif, grâce à des
matches basés sur la forme et le contenu:
a = 1
{c,d} = {2, 3}
[e,f,g] = [4, 5, 6]
"Elixir " <> rest = "Elixir rocks"
=> # rest => "rocks"
[ head | tail ] = [ 1, 2, 3, 4, 5, 6 ]
=> # head => 1
# tail => [ 2, 3, 4 ,5 ,6]
^a = 2
=> ** (MatchError) no match of right hand side value: 2
Pattern matching
• Le pattern matching est utilisable partout, dans les fonctions, les cases, etc.
Exemple “case”:
case File.open("myfile") do
{ :ok, device } -> IO.read(device, :line)
{ :error, reason } -> IO.puts "FAILED #{reason}"
end
Pattern matching
• Le pattern matching est utilisable partout, dans les fonctions, les cases, etc.
Exemple fonctions anonymes:
my_fun = fn
:plus, a, b -> a + b
:times, a, b -> a * b
end
IO.puts my_fun.(:plus, 3, 4) # => 7
IO.puts my_fun.(:times, 3, 4) # => 12
def other_fun(:minus, a, b), do: a - b
def other_fun(:divide, a, b), do: a/b
Pattern matching
• Le pattern matching permet d’écrire un code fonctionnel, proche des
spécifications mathématiques:
Exemple: Fibonacci. La spécification est:
fib(0) ⟶ 0
fib(1) ⟶ 1
fib(n) ⟶ fib(n-1) + fib(n-2)
Pattern matching
• Le pattern matching permet d’écrire un code fonctionnel, proche des
spécifications mathématiques:
Exemple: Fibonacci. Pattern match 1:
defmodule Fib do
def fib(n) do
if n < 2 do
n
else
fib(n-1) + fib(n-2)
end
end
end
Pattern matching
• Le pattern matching permet d’écrire un code fonctionnel, proche des
spécifications mathématiques:
Exemple: Fibonacci. Pattern match 2:
defmodule Fib do
def fib(n) do
case n do
0 -> 0
1 -> 1
n -> fib(n-1) + fib(n-2)
end
end
end
Pattern matching
• Le pattern matching permet d’écrire un code fonctionnel, proche des
spécifications mathématiques:
Exemple: Fibonacci. Pattern match 3:
defmodule Fib do
def fib(0), do: 0
def fib(1), do: 1
def fib(n), do: fib(n-1) + fib(n-2)
end
A comparer à:
fib(0) ⟶ 0
fib(1) ⟶ 1
fib(n) ⟶ fib(n-1) + fib(n-2)
Les fonctions transforment les données: Les
"pipes" |>
• Un langage fonctionnel est basé sur des fonctions que l’on compose entre
elles pour transformer des données.
invite_template = read_email_template(:invite)
users = DB.ParisExUsers
emails = format_emails(users, invite_template)
send_invite_emails(emails)
• Il s’agit d’une composition de fonctions:
send_invite(format_emails(DB.ParisExUsers, read_email_template(:invite)))
Les fonctions transforment les données: Les
"pipes" |>
• Le pipeline est plus clair grâce au “sucre syntaxique” d’Elixir:
invite_template = read_email_template(:invite)
DB.ParisExUsers
|> format_emails(invite_template)
|> send_invite_emails
• Attention à ce que le premier paramètre de vos fonctions soit bien la donnée à
transformer et ce que les paramètres suivants soient bien les “options”.
Les macros Elixir sont au coeur du langage
• Exécutée pour transformer le code à la compilation.
• Inspirée de Lisp: quote / unquote: Injection de code non-exécuté à la
compilation:
• quote: injecter du code à la compilation
• unquote: merger avec du code inclut passé à la macro
• Elles ont sauvé (littéralement) le langage.
Attention !
• Les macros permettent de créer des DSL utiles, mais ne jamais utiliser une
macro lorsque l’on peut utiliser une fonction.
• Elle vous permettre de réécrire des parties du langage donc peuvent rendre le
code plus obscur et fragile en cas d’abus.
Exemple de macro: If clause
defmodule My do
defmacro if(condition, clauses) do
do_clause = Keyword.get(clauses, :do, nil)
else_clause = Keyword.get(clauses, :else, nil)
quote do
case unquote(condition) do
val when val in [false, nil] -> unquote(else_clause)
_ -> unquote(do_clause)
end
end
end
end
Exemple de macro: If clause
defmodule Test do
require My
My.if 1 == 2 do
IO.puts "1 == 2"
else
IO.puts "1 != 2"
end
end
Usage:
$ elixir myif.exs
1 != 2
Elixir et les protocoles
• Les protocoles sont la manières dont Elixir implémente le polymorphisme.
• Ils permettent:
• d’implémenter des fonctionnalités dans un module sans avoir à modifier le
code du module
• d’abstraire un comportement commun à un ensemble de module mais de
permettre de spécialiser / surcharger le comportement.
• d’étendre le langage avec ses propres modules tout en s’intégrant
élégamment dans le langage Elixir.
Exemple: Le protocole inspect
• Voici la définition du protocole Inspect:
defprotocol Inspect do
@fallback_to_any true
def inspect(thing, opts)
end
• Ce protocole permet d’afficher de manière élégante des structures de
données, y compris vos propres structures.
Implémenter le protocole Inspect
Un cas typique consiste à impriment Inspect dans une struct:
defmodule User do
defstruct name: "John", age: 27
defimpl Inspect do
def inspect(%User{name: name, age: age}, _opts) do
"username is #{name} and age is #{age}"
end
end
end
Implémenter le protocole Inspect
• Voici le code qui démontre l’usage d’Inspect pour notre struct:
defmodule Test do
require User
users = [%User{},
%User{name: "Meg", age: 30},
%User{name: "Luke", age: 28}]
Enum.each users, fn user ->
IO.puts "#{inspect user}"
end
end
Usage:
$ elixir example_inspect.exs
username is John and age is 27
username is Meg and age is 30
username is Luke and age is 28
Redefinir une implémentation de protocole
• Interactive Elixir (1.1.1) - press Ctrl+C to exit (type h() ENTER for
help)
• iex(1)> inspect self
• "#PID<0.57.0>"
• iex(2)> defimpl Inspect, for: PID do
• ...(2)> def inspect(pid, _) do
• ...(2)> "Mon identifiant de process est "
<> :erlang.list_to_binary(:erlang.pid_to_list(pid))
• ...(2)> end
• ...(2)> end
• iex:2: warning: redefining module Inspect.PID
• {:module, Inspect.PID, …}
• iex(3)> inspect self
• "Mon identifiant de process est <0.57.0>"
Conclusion
• Je reprends les termes de Dave Thomas, l’auteur de “Programming Elixir” et
le co-fondateur de “The Pragmatic Programmers”:
Pensons différemment !
• Elixir est une opportunité
• Ne recréons pas l’environnement d’où nous venons
• Amusons-nous
Rendez-vous le 25 novembre 2015

2015: L'année d'Elixir, Code, écosystème et communauté

  • 1.
    2015 - L’annéed’Elixir : Les raisons du succès. 13 octobre 2015 Mickaël Rémond <mremond@process-one.net>
  • 2.
    2015: L’année d’Elixir:Code, écosystème et communauté
  • 3.
    La communauté Elixiren effervescence • En développement depuis 2011. Le développement s’accélère depuis que le language est stable. Elixir 1.0 publié en septembre 2014, suivi de Elixir 1.1 en septembre 2015. • Sortie du Framework de développement Web Phoenix en août 2015 en version 1.0.
  • 4.
    Elixir - 9Jan 2011 - README first commit
  • 5.
    Elixir - 10Jan 2011 - Added basic lexer
  • 6.
    Elixir - +de 4 ans après 1.0.0 1.1.0 8867 commits - 365 contributeurs
  • 7.
    Elixir - +de 4 ans après 131k lignes de code
  • 8.
    Le Framework Phoenix,le "Rails" d’Elixir ?
  • 9.
    La communauté Elixirrevitalise Erlang • Une influence majeure sur la VM Erlang: • Maps et optimisation des performances. • Hex.pm • Réflexion sur le langage
  • 10.
    Elixir, l’explosion, laseconde jeunesse d'Erlang
  • 11.
    Une communauté activeet décentralisée • La participation aux conférences Elixir est en forte augmentation. 250 participants cette année à la conférence Elixir à Austin • Des “meetups” dans le monde entier
  • 12.
    Publications • 7 livrespubliés ou en cours sur le sujet.
  • 13.
    Les forces dulangage: Ecosystème, influence et communauté • Des outils pensés dès la conception du langage pour la productivité: • Mix • Hex.pm • exUnit • Phoenix, • exrm, … • Un langage mêlant les influences: • Influence d’Erlang (car construit sur la VM Erlang). • Influence de Ruby et de Rails • Influence de Lisp, C#, Python, Haskell, etc… • Une communauté ouverte et accueillante. Les débutants sont accompagnés. Le langage attire des développeurs auparavant rebuté par la syntaxe d’Erlang.
  • 14.
    Cas d’usage modernes •Elixir est bien adapté: • aux systèmes de messaging en général: • Exemples: ProcessOne / ejabberd. • pour le développement Web, d’API et de “micro-services”, grâce au framework Phoenix. • Exemples: Plataformatec, Brightcove, Shopping Adventure • au développement de DSL (Domain Specific Languages), grâce au système de macros évolué d’Elixir, • Les plates-formes transactionnelles de masse: Jeu vidéo, finance. • Exemples: Undead Labs • à l’informatique embarquée (Raspberry Pi, Beagle board). • Exemples: Rose Point Navigation Systems. • à la gestion de la masse de signaux produits par l’Internet of Things.
  • 15.
  • 16.
    Les idées fortesd'Elixir • Pattern matching • Les fonctions transforment les données: Les "pipes" |> • Meta-Programmation s’appuyant sur les macros. • Extensibilité / Polymorphisme: Protocols. • Shell puissant pour le debug et la gestion d’une plate-forme de production. • Documentation dans le code accessible depuis la ligne de commande. • “For Comprehension” / into. • Performance et clustering natif. • Compatibilité avec Erlang. Réutilise des années de travail sur la distribution et le parallélisme et des centaines de milliers de ligne de code. • Upgrade de code à chaud et release. • Les patterns Erlang OTP: Supervisors, servers, etc
  • 17.
    Pattern matching • Lepattern matching permet d’écrire un code plus expressif, grâce à des matches basés sur la forme et le contenu: a = 1 {c,d} = {2, 3} [e,f,g] = [4, 5, 6] "Elixir " <> rest = "Elixir rocks" => # rest => "rocks" [ head | tail ] = [ 1, 2, 3, 4, 5, 6 ] => # head => 1 # tail => [ 2, 3, 4 ,5 ,6] ^a = 2 => ** (MatchError) no match of right hand side value: 2
  • 18.
    Pattern matching • Lepattern matching est utilisable partout, dans les fonctions, les cases, etc. Exemple “case”: case File.open("myfile") do { :ok, device } -> IO.read(device, :line) { :error, reason } -> IO.puts "FAILED #{reason}" end
  • 19.
    Pattern matching • Lepattern matching est utilisable partout, dans les fonctions, les cases, etc. Exemple fonctions anonymes: my_fun = fn :plus, a, b -> a + b :times, a, b -> a * b end IO.puts my_fun.(:plus, 3, 4) # => 7 IO.puts my_fun.(:times, 3, 4) # => 12 def other_fun(:minus, a, b), do: a - b def other_fun(:divide, a, b), do: a/b
  • 20.
    Pattern matching • Lepattern matching permet d’écrire un code fonctionnel, proche des spécifications mathématiques: Exemple: Fibonacci. La spécification est: fib(0) ⟶ 0 fib(1) ⟶ 1 fib(n) ⟶ fib(n-1) + fib(n-2)
  • 21.
    Pattern matching • Lepattern matching permet d’écrire un code fonctionnel, proche des spécifications mathématiques: Exemple: Fibonacci. Pattern match 1: defmodule Fib do def fib(n) do if n < 2 do n else fib(n-1) + fib(n-2) end end end
  • 22.
    Pattern matching • Lepattern matching permet d’écrire un code fonctionnel, proche des spécifications mathématiques: Exemple: Fibonacci. Pattern match 2: defmodule Fib do def fib(n) do case n do 0 -> 0 1 -> 1 n -> fib(n-1) + fib(n-2) end end end
  • 23.
    Pattern matching • Lepattern matching permet d’écrire un code fonctionnel, proche des spécifications mathématiques: Exemple: Fibonacci. Pattern match 3: defmodule Fib do def fib(0), do: 0 def fib(1), do: 1 def fib(n), do: fib(n-1) + fib(n-2) end A comparer à: fib(0) ⟶ 0 fib(1) ⟶ 1 fib(n) ⟶ fib(n-1) + fib(n-2)
  • 24.
    Les fonctions transformentles données: Les "pipes" |> • Un langage fonctionnel est basé sur des fonctions que l’on compose entre elles pour transformer des données. invite_template = read_email_template(:invite) users = DB.ParisExUsers emails = format_emails(users, invite_template) send_invite_emails(emails) • Il s’agit d’une composition de fonctions: send_invite(format_emails(DB.ParisExUsers, read_email_template(:invite)))
  • 25.
    Les fonctions transformentles données: Les "pipes" |> • Le pipeline est plus clair grâce au “sucre syntaxique” d’Elixir: invite_template = read_email_template(:invite) DB.ParisExUsers |> format_emails(invite_template) |> send_invite_emails • Attention à ce que le premier paramètre de vos fonctions soit bien la donnée à transformer et ce que les paramètres suivants soient bien les “options”.
  • 26.
    Les macros Elixirsont au coeur du langage • Exécutée pour transformer le code à la compilation. • Inspirée de Lisp: quote / unquote: Injection de code non-exécuté à la compilation: • quote: injecter du code à la compilation • unquote: merger avec du code inclut passé à la macro • Elles ont sauvé (littéralement) le langage. Attention ! • Les macros permettent de créer des DSL utiles, mais ne jamais utiliser une macro lorsque l’on peut utiliser une fonction. • Elle vous permettre de réécrire des parties du langage donc peuvent rendre le code plus obscur et fragile en cas d’abus.
  • 27.
    Exemple de macro:If clause defmodule My do defmacro if(condition, clauses) do do_clause = Keyword.get(clauses, :do, nil) else_clause = Keyword.get(clauses, :else, nil) quote do case unquote(condition) do val when val in [false, nil] -> unquote(else_clause) _ -> unquote(do_clause) end end end end
  • 28.
    Exemple de macro:If clause defmodule Test do require My My.if 1 == 2 do IO.puts "1 == 2" else IO.puts "1 != 2" end end Usage: $ elixir myif.exs 1 != 2
  • 29.
    Elixir et lesprotocoles • Les protocoles sont la manières dont Elixir implémente le polymorphisme. • Ils permettent: • d’implémenter des fonctionnalités dans un module sans avoir à modifier le code du module • d’abstraire un comportement commun à un ensemble de module mais de permettre de spécialiser / surcharger le comportement. • d’étendre le langage avec ses propres modules tout en s’intégrant élégamment dans le langage Elixir.
  • 30.
    Exemple: Le protocoleinspect • Voici la définition du protocole Inspect: defprotocol Inspect do @fallback_to_any true def inspect(thing, opts) end • Ce protocole permet d’afficher de manière élégante des structures de données, y compris vos propres structures.
  • 31.
    Implémenter le protocoleInspect Un cas typique consiste à impriment Inspect dans une struct: defmodule User do defstruct name: "John", age: 27 defimpl Inspect do def inspect(%User{name: name, age: age}, _opts) do "username is #{name} and age is #{age}" end end end
  • 32.
    Implémenter le protocoleInspect • Voici le code qui démontre l’usage d’Inspect pour notre struct: defmodule Test do require User users = [%User{}, %User{name: "Meg", age: 30}, %User{name: "Luke", age: 28}] Enum.each users, fn user -> IO.puts "#{inspect user}" end end Usage: $ elixir example_inspect.exs username is John and age is 27 username is Meg and age is 30 username is Luke and age is 28
  • 33.
    Redefinir une implémentationde protocole • Interactive Elixir (1.1.1) - press Ctrl+C to exit (type h() ENTER for help) • iex(1)> inspect self • "#PID<0.57.0>" • iex(2)> defimpl Inspect, for: PID do • ...(2)> def inspect(pid, _) do • ...(2)> "Mon identifiant de process est " <> :erlang.list_to_binary(:erlang.pid_to_list(pid)) • ...(2)> end • ...(2)> end • iex:2: warning: redefining module Inspect.PID • {:module, Inspect.PID, …} • iex(3)> inspect self • "Mon identifiant de process est <0.57.0>"
  • 34.
    Conclusion • Je reprendsles termes de Dave Thomas, l’auteur de “Programming Elixir” et le co-fondateur de “The Pragmatic Programmers”: Pensons différemment ! • Elixir est une opportunité • Ne recréons pas l’environnement d’où nous venons • Amusons-nous
  • 35.
    Rendez-vous le 25novembre 2015