Slide 1

Slide 1 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix From Front-End to Full Stack With Elixir & Phoenix

Slide 2

Slide 2 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 bit.ly/front-end-to-full-stack

Slide 3

Slide 3 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 LAUREN TAN

Slide 4

Slide 4 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 5

Slide 5 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 6

Slide 6 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 7

Slide 7 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 ! SUGARPIRATE_ " POTETO

Slide 8

Slide 8 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 ZELDA

Slide 9

Slide 9 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 10

Slide 10 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix A long time ago in a galaxy far, far away….

Slide 11

Slide 11 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix

Slide 12

Slide 12 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix

Slide 13

Slide 13 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix

Slide 14

Slide 14 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix ☠

Slide 15

Slide 15 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 16

Slide 16 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix JavaScript

Slide 17

Slide 17 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix let foo = [1, 2, 3, 4, 5]; let bar = foo.map((n) => n + 1); // [2, 3, 4, 5, 6] let baz = bar.filter((n) => n >=3 && n <= 5); // [3, 4, 5] let qux = baz.reduce((n, el) => n += el); // 12 console.log(foo); // [1, 2, 3, 4, 5]

Slide 18

Slide 18 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix let f = R.pipe(Math.pow, R.negate, R.inc); f(3, 4); // -(3^4) + 1

Slide 19

Slide 19 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix

Slide 20

Slide 20 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix

Slide 21

Slide 21 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 MVC

Slide 22

Slide 22 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 ember-changeset https://github.com/DockYard/ember-changeset

Slide 23

Slide 23 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 {{dummy-form changeset=(changeset user EmployeeValidations) submit=(action "submit") rollback=(action "rollback") }}

Slide 24

Slide 24 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 https://facebook.github.io/react

Slide 25

Slide 25 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 http://redux.js.org/

Slide 26

Slide 26 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 I. Learn You Some Elixir for Great Good! II. Phoenix is Not Rails III.OOPs

Slide 27

Slide 27 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 I. Learn You Some Elixir for Great Good! II. Phoenix is Not Rails III.OOPs

Slide 28

Slide 28 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix Elixir

Slide 29

Slide 29 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix

Slide 30

Slide 30 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix https://www.youtube.com/watch?v=rRbY3TMUcgQ

Slide 31

Slide 31 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix Domain Logic Domain Logic Domain Logic Domain Logic Web Umbrella App

Slide 32

Slide 32 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix https://www.manning.com/books/elixir-in-action https://www.manning.com/books/the-little-elixir-and-otp-guidebook

Slide 33

Slide 33 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 |>i|>e

Slide 34

Slide 34 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 foo(bar(baz(123), 456), 789)

Slide 35

Slide 35 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 123 |> baz() |> bar(456) |> foo(123)

Slide 36

Slide 36 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Sugar?

Slide 37

Slide 37 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Small Functions

Slide 38

Slide 38 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 def serialize(user) do user |> serialize_attributes() |> serialize_relationships() |> to_json() end

Slide 39

Slide 39 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 def validate_presence(input) do if input == "" do "Can't be blank" end input end

Slide 40

Slide 40 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Pattern Matching

Slide 41

Slide 41 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 def validate_presence(""), do: {:err, "Can't be blank"} def validate_presence(input), do: input

Slide 42

Slide 42 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule MyPlug do import Plug.Conn def init(opts), do: opts def call(conn, currency: currency) do case currency do "USD" -> assign(conn, :greeting, "murica") "CAD" -> assign(conn, :greeting, "eh?") "AUD" -> assign(conn, :greeting, "oi mate") _ -> conn end end end

Slide 43

Slide 43 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule MyPlug do import Plug.Conn def init(opts), do: opts def call(conn, currency: currency) do greet(conn, currency) end def greet(conn, "USD"), do: assign(conn, :greeting, "murica") def greet(conn, "CAD"), do: assign(conn, :greeting, "eh?") def greet(conn, "AUD"), do: assign(conn, :greeting, "oi mate") def greet(conn, _), do: conn end

Slide 44

Slide 44 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule WebhookMailer do use Phoenix.Swoosh, view: MyApp.EmailView, layout: {MyApp.LayoutView, :email} alias MyApp.User def webhook(topic, %User{first_name: first_name, last_name: last_name, email: email}) do title = title_for(topic) new |> to({"#{first_name} #{last_name}", email}) |> from({"Patrick", "hello.this.is@patri.ck"}) |> subject(title) |> render_body("webhook.html", %{title: title, first_name: first_name}) end # ... end

Slide 45

Slide 45 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defp title_for("customer_created"), do: "Created account successfully" defp title_for("customer_transfer_created"), do: "Transfer created" defp title_for("customer_transfer_cancelled"), do: "Transfer cancelled" defp title_for("customer_transfer_failed"), do: "Transfer failed" defp title_for("customer_transfer_completed"), do: "Transfer completed" defp title_for("customer_funding_source_added"), do: "Funding source added" defp title_for("customer_funding_source_removed"), do: "Funding source removed" defp title_for("customer_verified"), do: "Your account was verified" defp title_for("customer_suspended"), do: "Your account was suspended" defp title_for("customer_verification_documentation_needed"), do: "Documentation needed" defp title_for("customer_verification_documentation_uploaded"), do: "Documentation uploaded" defp title_for("customer_verification_documentation_approved"), do: "Documentation approved" defp title_for(message), do: message

Slide 46

Slide 46 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Recursion

Slide 47

Slide 47 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 { "id": "1", "foo": { "bar": { "qux": "hello world" }, "baz": 123 } }

Slide 48

Slide 48 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Json do def flatten(%{} = json) do json |> Map.to_list() # [foo: %{bar: %{qux: "hello world"}, baz: 123}, id: "1"] |> to_flat_map(%{}) end def flatten(%{} = json) when json == %{}, do: %{} # ... end

Slide 49

Slide 49 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 bae's case

Slide 50

Slide 50 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defp to_flat_map([], acc), do: acc

Slide 51

Slide 51 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Add to accumulator

Slide 52

Slide 52 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defp to_flat_map([{_k, %{} = v} | t], acc) do v |> Map.to_list() |> to_flat_map(to_flat_map(t, acc)) end

Slide 53

Slide 53 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Flatten all the things

Slide 54

Slide 54 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defp to_flat_map([{k, v} | t], acc) do to_flat_map(t, Map.put_new(acc, k, v)) end

Slide 55

Slide 55 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 %{id: "1", foo: %{bar: %{qux: "hello world"}, baz: 123}} |> Json.flatten() |> IO.inspect() # %{baz: 123, id: "1", qux: "hello world"}

Slide 56

Slide 56 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Json do def flatten(%{} = json) when json == %{}, do: %{} def flatten(%{} = json) do json |> Map.to_list() |> to_flat_map(%{}) end defp to_flat_map([{_k, %{} = v} | t], acc), do: to_flat_map(Map.to_list(v), to_flat_map(t, acc)) defp to_flat_map([{k, v} | t], acc), do: to_flat_map(t, Map.put_new(acc, k, v)) defp to_flat_map([], acc), do: acc end

Slide 57

Slide 57 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Data Types https://engineering.appcues.com/2016/02/02/too-many-dicts.html

Slide 58

Slide 58 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Maps

Slide 59

Slide 59 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 %{ "data" => %{ "type" => "articles", "id" => "1" } }

Slide 60

Slide 60 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 61

Slide 61 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 %{ id: "1", name: "Bob" }

Slide 62

Slide 62 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Structs

Slide 63

Slide 63 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Employee do @enforce_keys [:id] defstruct id: nil, name: nil @type t :: %Employee{id: pos_integer, name: String.t} end defmodule Team do defstruct name: nil, employees: [] @type t :: %Team{name: String.t, employees: [Employee.t, ...]} end

Slide 64

Slide 64 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Employee do # ... def promote(%Employee{salary: salary} = employee, pay_rise) do %{employee | salary: round(salary * (1 + pct_increase))} end end defmodule Team do # ... def promote_all(%Team{employees: employees}, bonus) do Enum.map(employees, &(Employee.promote(&1, bonus))) end end

Slide 65

Slide 65 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 bob = %Employee{id: "1", name: "Bob", salary: 80_000} jane = %Employee{id: "2", name: "Jane", salary: 100_000} team = %Team{name: "Accounting", employees: [bob, jane]} # %Team{employees: [%Employee{id: "1", name: "Bob", salary: 80000}, # %Employee{id: "2", name: "Jane", salary: 100000}], name: "Accounting"} Team.promote_all(team, 0.2) # 20% pay rise # [%Employee{id: "1", name: "Bob", salary: 96000}, # %Employee{id: "2", name: "Jane", salary: 120000}]

Slide 66

Slide 66 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Tuples

Slide 67

Slide 67 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 {:ok, result}

Slide 68

Slide 68 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 {:ok, result} {:err, "message"}

Slide 69

Slide 69 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Foo do def serialize(user) do with {:ok, serialized} <- serialize_attributes(user), {:ok, serialized} <- serialize_relationships(serialized), do: to_json(serialized) end def serialize_attributes(user), do: {:ok, user} def serialize_relationships(user), do: {:ok, user} def to_json(map), do: Poison.encode!(map) end

Slide 70

Slide 70 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Keywords

Slide 71

Slide 71 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 def to_currency(value, currency: "USD", cents?: cents?), do: # ...

Slide 72

Slide 72 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Protocols

Slide 73

Slide 73 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 74

Slide 74 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Team do # ... defimpl Enumerable do def count(%Team{employees: employees}), do: {:ok, length(employees)} end end

Slide 75

Slide 75 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 team # %Team{employees: [%Employee{id: "1", name: "Bob", salary: 80000}, # %Employee{id: "2", name: "Jane", salary: 100000}], name: "Accounting"} Enum.count(team) # 2

Slide 76

Slide 76 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Team do # ... defimpl Enumerable do def count(%Team{employees: employees}), do: {:ok, length(employees)} def member?(_, _), do: {:error, __MODULE__} def reduce(%Team{employees: employees}, acc, fun), do: do_reduce(employees, acc, fun) # default list reducer defp do_reduce(_, {:halt, acc}, _fun), do: {:halted, acc} defp do_reduce(list, {:suspend, acc}, fun), do: {:suspended, acc, &do_reduce(list, &1, fun)} defp do_reduce([], {:cont, acc}, _fun), do: {:done, acc} defp do_reduce([h | t], {:cont, acc}, fun), do: do_reduce(t, fun.(h, acc), fun) end end

Slide 77

Slide 77 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 bob = %Employee{id: "1", name: "Bob", salary: 10_000} jane = %Employee{id: "2", name: "Jane", salary: 20_000} team = %Team{name: "Accounting", employees: [bob, jane]} Enum.member?(team, bob) # true Enum.map(team, fn e -> e.name end) # ["Bob", "Jane"] Enum.max_by(team, fn e -> e.salary end) # %Employee{id: "2", name: "Jane", salary: 20000}

Slide 78

Slide 78 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Team do # ... def promote_all(%Team{employees: employees}, bonus) do Enum.map(employees, &(Employee.promote(&1, bonus))) end end

Slide 79

Slide 79 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Team do # ... def promote_all(%Team{} = team, bonus) do Enum.map(team, &(Employee.promote(&1, bonus))) end end

Slide 80

Slide 80 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Behaviours

Slide 81

Slide 81 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Interface

Slide 82

Slide 82 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Request do defstruct headers: %{}, body: %{} end

Slide 83

Slide 83 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Validator do @callback validate(request :: Request.t, attribute :: :atom) :: %{} @callback valid?(value :: any) :: boolean @optional_callbacks valid?: 1 end

Slide 84

Slide 84 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Validator.Presence do @behaviour Validator def validate(%Request{body: body}, attribute) do valid?(Map.get(body, attribute)) end def valid?(nil), do: false def valid?(%{} = map) when map === %{}, do: false def valid?([]), do: false def valid?(_), do: true end

Slide 85

Slide 85 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 warning: undefined behaviour function validate/2 (for behaviour Validator) lib/examples/behaviours.ex:10 warning: undefined behaviour function valid?/1 (for behaviour Validator) lib/examples/behaviours.ex:10

Slide 86

Slide 86 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 # behaviours.ex:15: The call 'Elixir.Map':get(body@1::[],attribute@1::any()) will # never return since the success typing is (map(),any()) -> any() # and the contract is (map(),key()) -> value()

Slide 87

Slide 87 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 $ mix dialyzer https://github.com/jeremyjh/dialyxir

Slide 88

Slide 88 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 @spec https://medium.com/@barruumrex/seeking-simple-satisfaction-2a098902ddff

Slide 89

Slide 89 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Macros

Slide 90

Slide 90 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 91

Slide 91 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Elixir is written in Elixir

Slide 92

Slide 92 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 93

Slide 93 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 94

Slide 94 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 elixir/lib/elixir/src/elixir_bootstrap.erl

Slide 95

Slide 95 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 # Use elixir_bootstrap module to be able to bootstrap Kernel. # The bootstrap module provides simpler implementations of the # functions removed, simple enough to bootstrap. import Kernel, except: [@: 1, defmodule: 2, def: 1, def: 2, defp: 2, defmacro: 1, defmacro: 2, defmacrop: 2] import :elixir_bootstrap defmodule Kernel do # ... end

Slide 96

Slide 96 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Erlang compiles Elixir

Slide 97

Slide 97 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 -export(['MACRO-def'/2, 'MACRO-def'/3, 'MACRO-defp'/3, 'MACRO-defmodule'/3, 'MACRO-defmacro'/2, 'MACRO-defmacro'/3, 'MACRO-defmacrop'/3, 'MACRO-@'/2, '__info__'/1]).

Slide 98

Slide 98 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 99

Slide 99 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Kernel.SpecialForms

Slide 100

Slide 100 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmacro unquote(:%{})(args), do: error!([args])

Slide 101

Slide 101 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 expand({'%{}', Meta, Args}, E) -> elixir_map:expand_map(Meta, Args, E);

Slide 102

Slide 102 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 expand_map(Meta, [{'|', UpdateMeta, [Left, Right]}], E) -> {[ELeft | ERight], EA} = elixir_exp:expand_args([Left | Right], E), validate_kv(Meta, ERight, Right, E), {{'%{}', Meta, [{'|', UpdateMeta, [ELeft, ERight]}]}, EA}; expand_map(Meta, Args, E) -> {EArgs, EA} = elixir_exp:expand_args(Args, E), validate_kv(Meta, EArgs, Args, E), {{'%{}', Meta, EArgs}, EA}.

Slide 103

Slide 103 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 :math.pi # 3.141592653589793

Slide 104

Slide 104 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 :maps.new() === %{} # true

Slide 105

Slide 105 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule CowSay do defmacro __using__(_) do quote do def cowsay(str) do """ #{make_line("_", String.length(str))} < #{str} > #{make_line("-", String.length(str))} \\ ^__^ \\ (oo)\\_______ (__)\\ )\\/\\ ||----w | || || """ |> IO.puts() end defp make_line(char, len), do: String.duplicate(char, len + 1) end end end

Slide 106

Slide 106 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Bob do use CowSay end Bob.cowsay("It's me Bob")

Slide 107

Slide 107 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 108

Slide 108 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 https://pragprog.com/book/cmelixir/metaprogramming-elixir

Slide 109

Slide 109 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 I. Learn You Some Elixir for Great Good! II. Phoenix is Not Rails III.OOPs

Slide 110

Slide 110 text

ElixirConf 2016 From Front-End to Full Stack with Elixir & Phoenix

Slide 111

Slide 111 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 112

Slide 112 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Pipelines

Slide 113

Slide 113 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 lib/my_app/endpoint.ex

Slide 114

Slide 114 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 conn

Slide 115

Slide 115 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 conn

Slide 116

Slide 116 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 conn

Slide 117

Slide 117 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 conn

Slide 118

Slide 118 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 conn conn Endpoint Router Controller DB Pipeline 200 OK Ecto View

Slide 119

Slide 119 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 def phoenix(conn, _opts) do conn |> endpoint() |> router() |> pipeline() |> controller() |> view() end

Slide 120

Slide 120 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Phoenix is a pipeline

Slide 121

Slide 121 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Composed of pipelines

Slide 122

Slide 122 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Made out of plugs

Slide 123

Slide 123 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 And functions

Slide 124

Slide 124 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 125

Slide 125 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Plug

Slide 126

Slide 126 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 127

Slide 127 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 def my_plug(conn, _opts) do conn end

Slide 128

Slide 128 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule MyApp.Authorization do import Plug.Conn def init(opts), do: opts def call(conn, opts) do # ... end end

Slide 129

Slide 129 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule MyApp.Router do use MyApp.Web, :router pipeline :authorized do plug MyApp.Authorization end scope "/api", MyApp do pipe_through :authorized scope "/v1", Api.V1 do get "/status", StatusController, :index end end end

Slide 130

Slide 130 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule MyApp.WebhookController do use MyApp.Web, :controller plug :verify_request_signature def create(conn, # ...) do # ... end defp verify_request_signature(conn, _) do # ... end end

Slide 131

Slide 131 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 pipeline :json_api do plug :accepts, ["json", "json-api"] plug :fetch_session plug JaSerializer.ContentTypeNegotiation plug JaSerializer.Deserializer end

Slide 132

Slide 132 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 scope "/api", MyApp do pipe_through :json_api # public routes get "/foo", FooController, :index scope "/v1", Api.V1 do pipe_through :authorized resources "/users", UserController: only: [:index, :show] end end

Slide 133

Slide 133 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 lib/my_app/endpoint.ex

Slide 134

Slide 134 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule MyApp.Endpoint do use Phoenix.Endpoint, otp_app: :my_app socket "/socket", MyApp.UserSocket plug Plug.Static, at: "/", from: :my_app, gzip: false, only: ~w(css fonts images js favicon.ico robots.txt) if code_reloading? do plug Phoenix.CodeReloader end plug Plug.RequestId plug Plug.Logger plug Plug.Parsers, parsers: [:urlencoded, :multipart, :json], pass: ["*/*"], json_decoder: Poison plug Plug.MethodOverride plug Plug.Head plug Plug.Session, store: :cookie, key: "_my_app_key", signing_salt: "BKi/ZZMd" plug MyApp.Router end

Slide 135

Slide 135 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Fractal

Slide 136

Slide 136 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Terraform https://github.com/poteto/terraform

Slide 137

Slide 137 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Incremental Phoenix

Slide 138

Slide 138 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 iex(1)> [info] GET /v1/foo [debug] Processing by MyApp.FooController.index/2 Parameters: %{} Pipelines: [:api] [info] Sent 200 in 22ms [info] GET /v1/bar [debug] Processing by MyApp.BarController.index/2 Parameters: %{} Pipelines: [:api] [info] Sent 200 in 116µs [info] GET /v1/hello-world # forwarded to legacy API [info] Sent 200 in 1ms [info] GET /v1/gifs/search # forwarded to legacy API [info] Sent 200 in 102ms

Slide 139

Slide 139 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule MyApp.Endpoint do # ... plug MyApp.ForwardRequest, client: MyApp.Forwarders.Giphy, router: MyApp.Router plug MyApp.Router end

Slide 140

Slide 140 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule MyApp.ForwardRequest do import Plug.Conn def init(opts), do: opts def call(conn, client: client, router: router) do routes = router.__routes__ # conn |> match_route(routes) |> handle_request(client) |> send_response() end # ... end

Slide 141

Slide 141 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 142

Slide 142 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 143

Slide 143 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmacro __before_compile__(_env) do quote location: :keep do defoverridable [call: 2] def call(conn, opts) do try do super(conn, opts) catch kind, reason -> Plug.ErrorHandler.__catch__(conn, kind, reason, &handle_errors/2) end end end end

Slide 144

Slide 144 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 catch kind, reason -> # do our forward here end

Slide 145

Slide 145 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Terraform https://github.com/poteto/terraform

Slide 146

Slide 146 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule Terraform do defmacro __using__(opts) do quote location: :keep do Module.register_attribute __MODULE__, :terraformer, [] @terraformer Keyword.get(unquote(opts), :terraformer) @before_compile Terraform end end # ... end

Slide 147

Slide 147 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmacro __before_compile__(_env) do quote location: :keep do defoverridable [call: 2] def call(conn, opts) do try do super(conn, opts) catch _, %{conn: conn} -> terraform(conn, @terraformer) end end defp terraform(conn, terraformer) do terraformer.call(conn, []) end defoverridable [terraform: 2] end end

Slide 148

Slide 148 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule MyApp.Router do use Terraform, terraformer: MyApp.Terraformers.Foo # ... end

Slide 149

Slide 149 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 defmodule MyApp.Terraformers.Foo do alias MyApp.Clients.Foo # example client made with HTTPoison use Plug.Router plug :match plug :dispatch # match specific path get "/v1/hello-world", do: send_resp(conn, 200, "Hello world") # match all `get`s get _ do %{method: "GET", request_path: request_path, params: params, req_headers: req_headers} = conn res = Foo.get!(request_path, req_headers, [params: Map.to_list(params)]) send_response({:ok, conn, res}) end def send_response({:ok, conn, %{headers: headers, status_code: status_code, body: body}}) do conn = %{conn | resp_headers: headers} send_resp(conn, status_code, body) end end

Slide 150

Slide 150 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 I. Learn You Some Elixir for Great Good! II. Phoenix is Not Rails III.OOPs

Slide 151

Slide 151 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 152

Slide 152 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Design Patterns

Slide 153

Slide 153 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 154

Slide 154 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 155

Slide 155 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 156

Slide 156 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 –Sandi Metz “Duplication is far cheaper than the wrong abstraction.”

Slide 157

Slide 157 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 https://fsharpforfunandprofit.com/fppatterns/

Slide 158

Slide 158 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 State

Slide 159

Slide 159 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Objects

Slide 160

Slide 160 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 class Person { constructor(name) { this.name = name; this.x = 0; this.y = 0; } greet() { return `Hi there, my name is ${this.name}.`; } report() { return `I'm at (${this.x}, ${this.y}).`; } move(x = 0, y = 0) { this.x = x; this.y = y; } }

Slide 161

Slide 161 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 let bob = new Person('Bob'); bob.greet(); // "Hi there, my name is Bob." bob.report(); // "I'm at (0, 0)."

Slide 162

Slide 162 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 bob.move(1, 2); bob.report(); // "I'm at (1, 2)."

Slide 163

Slide 163 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 class Movable { constructor(x, y) { this.move(x, y); } move(x = 0, y = 0) { this.x = x; this.y = y; } report() { return `I'm at (${this.x}, ${this.y}).`; } }

Slide 164

Slide 164 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 class Person extends Movable { constructor(name) { super(); this.name = name; } greet() { return `Hi there, my name is ${this.name}.`; } }

Slide 165

Slide 165 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Data

Slide 166

Slide 166 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Function apple -> banana

Slide 167

Slide 167 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 .toBanana();

Slide 168

Slide 168 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 .toPineapple();

Slide 169

Slide 169 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Uncaught TypeError: .toPineapple is not a function(…)

Slide 170

Slide 170 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 171

Slide 171 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Function apple -> banana Function banana -> pineapple

Slide 172

Slide 172 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Function apple -> banana Function banana -> pineapple Composition

Slide 173

Slide 173 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Function apple -> pineapple

Slide 174

Slide 174 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Model the System

Slide 175

Slide 175 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016

Slide 176

Slide 176 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Transform the Data https://fsharpforfunandprofit.com/fppatterns/

Slide 177

Slide 177 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Fractal

Slide 178

Slide 178 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Function input output https://fsharpforfunandprofit.com/fppatterns/

Slide 179

Slide 179 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 low level operation low level operation low level operation EmailValidator Service email validated result https://fsharpforfunandprofit.com/fppatterns/

Slide 180

Slide 180 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 service service service UpdateProfile Use-case change profile request change profile result https://fsharpforfunandprofit.com/fppatterns/

Slide 181

Slide 181 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 use-case use-case use-case Web Application http request http response https://fsharpforfunandprofit.com/fppatterns/

Slide 182

Slide 182 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Web Application conn conn https://fsharpforfunandprofit.com/fppatterns/

Slide 183

Slide 183 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 tl;dr

Slide 184

Slide 184 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 I. Learn You Some Elixir for Great Good! II. Phoenix is Not Rails III.OOPs

Slide 185

Slide 185 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 I. Learn You Some Elixir for Great Good! II. Phoenix is Not Rails III.OOPs

Slide 186

Slide 186 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 I. Learn You Some Elixir for Great Good! II. Phoenix is Not Rails III.OOPs

Slide 187

Slide 187 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 LAUREN TAN ! SUGARPIRATE_ " POTETO

Slide 188

Slide 188 text

From Front-End to Full Stack with Elixir & Phoenix ElixirConf 2016 Thanks!