Slide 1

Slide 1 text

Tony Messias Maceió DEV Meetup #21 Phoenix for Laravel developers

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

This is not a hands-on talk.

Slide 4

Slide 4 text

I'm not going to teach you Elixir (or Phoenix) in 30~ish minutes.

Slide 5

Slide 5 text

I'm not saying that one is better than the other.

Slide 6

Slide 6 text

In fact, I'm actually showing that you can build shiny things with tools you already know.

Slide 7

Slide 7 text

This talk in a mind-map.

Slide 8

Slide 8 text

Functional Programming

Slide 9

Slide 9 text

Functional Programming

Slide 10

Slide 10 text

Haven't the Gods of programming decided that OOP has won this battle?

Slide 11

Slide 11 text

Why is functional programming in such a “hype” now?

Slide 12

Slide 12 text

What is a function? ● In math, functions are all about transforming input to output (sounds familiar?) ● You might be used to expressing functions in math like so: y = x * 2 or g = x ^ 2 ● But there is another notation that is much more expressive (IMO): f(x) = x * 2 f(5) = 5 * 2 f(5) = 10

Slide 13

Slide 13 text

f(x) = x * 2 --- const f = (x) => x * 2 var x = 5 assertEquals(f(x), 10) assertEquals(f(x), f(x)) source

Slide 14

Slide 14 text

class Value { constructor(val) { this.value = val; } } const f = (x) => x.value++ * 2 const x = new Value(5); console.log(f(x) == f(x)); // True or False? console.log(x.value); // What is the value?

Slide 15

Slide 15 text

class Value { constructor(val) { this.value = val; } } const f = (x) => x.value++ * 2 const x = new Value(5); console.log(f(x) == f(x)); // false console.log(x.value); // 7

Slide 16

Slide 16 text

Immutability ease distributing computation.

Slide 17

Slide 17 text

Concurrency and Parallelism

Slide 18

Slide 18 text

Parallelism Concurrency source

Slide 19

Slide 19 text

before I forget...

Slide 20

Slide 20 text

Slack'ish in Laravel tonysm/slackish-laravel Slack'ish in Phoenix tonysm/slackish-phoenix

Slide 21

Slide 21 text

Elixir, the good parts

Slide 22

Slide 22 text

defmodule SlackishphxWeb.CompanyController do use SlackishphxWeb, :controller plug SlackishphxWeb.Plugs.RequireAuth def create(conn, %{"company" => params}) do case Slackishphx.Auth.create_company(conn.assigns[:user], params) do {:ok, company} -> conn |> create_default_channel(company) |> switch_company(conn.assigns[:user], company) {:error, changeset} -> conn |> render("new.html", changeset: changeset) end end end

Slide 23

Slide 23 text

defmodule SlackishphxWeb.CompanyController do use SlackishphxWeb, :controller plug SlackishphxWeb.Plugs.RequireAuth def create(conn, %{"company" => params}) do case Slackishphx.Auth.create_company(conn.assigns[:user], params) do {:ok, company} -> conn |> create_default_channel(company) |> switch_company(conn.assigns[:user], company) {:error, changeset} -> conn |> render("new.html", changeset: changeset) end end end

Slide 24

Slide 24 text

defmodule SlackishphxWeb.CompanyController do use SlackishphxWeb, :controller plug SlackishphxWeb.Plugs.RequireAuth def create(conn, %{"company" => params}) do case Slackishphx.Auth.create_company(conn.assigns[:user], params) do {:ok, company} -> conn |> create_default_channel(company) |> switch_company(conn.assigns[:user], company) {:error, changeset} -> conn |> render("new.html", changeset: changeset) end end end

Slide 25

Slide 25 text

Phoenix, the good parts

Slide 26

Slide 26 text

MVC

Slide 27

Slide 27 text

Phoenix is not your application.

Slide 28

Slide 28 text

slackishphx/lib ├── slackishphx │ ├── application.ex │ ├── auth │ │ ├── auth.ex │ │ ├── company.ex │ │ └── user.ex │ ├── chat │ │ ├── channel.ex │ │ └── chat.ex │ └── repo.ex ├── slackishphx.ex ├── slackishphx_web │ ├── channels │ ├── controllers │ ├── endpoint.ex │ ├── gettext.ex │ ├── plugs │ ├── router.ex │ ├── templates │ └── views └── slackishphx_web.ex

Slide 29

Slide 29 text

slackishphx/lib ├── slackishphx │ ├── application.ex │ ├── auth │ │ ├── auth.ex │ │ ├── company.ex │ │ └── user.ex │ ├── chat │ │ ├── channel.ex │ │ └── chat.ex │ └── repo.ex ├── slackishphx.ex ├── slackishphx_web │ ├── channels │ ├── controllers │ ├── endpoint.ex │ ├── gettext.ex │ ├── plugs │ ├── router.ex │ ├── templates │ └── views └── slackishphx_web.ex

Slide 30

Slide 30 text

slackishphx/lib ├── slackishphx │ ├── application.ex │ ├── auth │ │ ├── auth.ex │ │ ├── company.ex │ │ └── user.ex │ ├── chat │ │ ├── channel.ex │ │ └── chat.ex │ └── repo.ex ├── slackishphx.ex ├── slackishphx_web │ ├── channels │ ├── controllers │ ├── endpoint.ex │ ├── gettext.ex │ ├── plugs │ ├── router.ex │ ├── templates │ └── views └── slackishphx_web.ex

Slide 31

Slide 31 text

Phoenix Channels

Slide 32

Slide 32 text

http://phoenixframework.org/blog/the-road-to-2-million-websocket-connections

Slide 33

Slide 33 text

Ecto

Slide 34

Slide 34 text

defmodule Slackishphx.Auth.User do use Ecto.Schema # ... schema "users" do field :name, :string field :email, :string field :google_id, :string field :google_token, :string field :avatar_path, :string belongs_to :current_company, Company has_many :companies, Company, foreign_key: :owner_id timestamps() end end

Slide 35

Slide 35 text

defmodule Slackishphx.Auth.User do # ... @doc false def register_from_google_changeset(%User{} = user, attrs) do user |> cast(attrs, [:name, :email, :google_id, ...]) |> validate_required([:name, :email, ...]) end end

Slide 36

Slide 36 text

defmodule Slackishphx.Auth do @moduledoc """ The Auth context. """ def create_company(%User{} = user, params) do changeset = user |> build_assoc(:companies) |> Company.create_company_changeset(params) Repo.insert(changeset) end end

Slide 37

Slide 37 text

The not so good parts...

Slide 38

Slide 38 text

deployment source

Slide 39

Slide 39 text

Comparisons*

Slide 40

Slide 40 text

Comparison Laravel (PHP) Phoenix (Elixir) Webapp (sessions) API (everything needs to go through HTTP) Pusher (websockets) Worker (broadcasting is delivered here) Database (sqlite) Queue Webapp (sessions) Channels (websockets) Database (sqlite)

Slide 41

Slide 41 text

Some similarities broadcast(new NewMessage( $request->user(), $channel, $request->input('content'), $request->input('uuid'), Carbon::now() )); broadcast!(socket, "rooms:#{room_id}:new", %{ message: message, user: user, uuid: uuid, time: DateTime.utc_now } )

Slide 42

Slide 42 text

Improvement points to Laravel Broadcast::channel('App.User.{id}', function ($user, $id) { return (int) $user->id === (int) $id; }); Broadcast::channel('channels.{channel}', function (\App\User $user, \App\Channel $channel) { if (!$channel->exists || !$user->canJoin($channel)) { return false; } $user->joinChannel($channel); return [ 'id' => $user->id, 'name' => $user->name, 'avatar_path' => $user->avatar_path, ]; }); channel "companies:*", SlackishphxWeb.CompanyChannel channel "rooms:*", SlackishphxWeb.RoomChannel

Slide 43

Slide 43 text

That's it!

Slide 44

Slide 44 text

References ● Functional Programming; What? Why? When? (Robert C Martin) https://www.youtube.com/watch?v=7Zlp9rKHGD4 ● Real World Elixir Deployment (Pete Gamache) https://www.youtube.com/watch?v=H686MDn4Lo8 ● Erlang: The Movie https://www.youtube.com/watch?v=xrIjfIjssLE ● Lonestar ElixirConf 2017- KEYNOTE: Phoenix 1.3 by Chris McCord https://www.youtube.com/watch?v=tMO28ar0lW8 ● GOTO 2016 • Phoenix a Web Framework for the New Web • José Valim https://www.youtube.com/watch?v=bk3icU8iIto

Slide 45

Slide 45 text

References ● ElixirConf 2016 - Giving up the Object-Oriented Ghost by Morgan Lanco https://www.youtube.com/watch?v=_VpZ6gQsyDY ● GOTO 2017 • Elixir: The only Sane Choice in an Insane World • Brian Cardarella https://www.youtube.com/watch?v=gom6nEvtl3U ● Elixir, quem é esse pokemon? - Bruno Volcov https://www.youtube.com/watch?v=aA-XHI-EYcM ● Ecto, você sabe o que é? - Amanda Sposito https://www.youtube.com/watch?v=hQM4VdEpz6g ● Programming Phoenix (book) by Chris McCord, Bruce Tate, and José Valim https://pragprog.com/book/phoenix/programming-phoenix