Upload
mickael-remond
View
649
Download
0
Embed Size (px)
Citation preview
2015 - L’année d’Elixir : Les raisons du succès.13 octobre 2015 Mickaël Rémond <[email protected]>
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ès131k 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 * bend
IO.puts my_fun.(:plus, 3, 4) # => 7IO.puts my_fun.(:times, 3, 4) # => 12
def other_fun(:minus, a, b), do: a - bdef 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 endend
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 endend
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 27username is Meg and age is 30username 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