Slide 1

Slide 1 text

Ruby on Rails vs Phoenix Framework 2015/06/02 #shinjukuex #10

Slide 2

Slide 2 text

self-introduction ! • Takayuki Matsubara @ma2ge/@ma2gedev • Application Engineer @ M3, Inc. • Rails/Java/JavaScript application • Ruby: breadcrumble, chrono_logger, bundle-star • Elixir: ltsvex, netrcex, qiita_ex • whisky

Slide 3

Slide 3 text

Phoenix contributors

Slide 4

Slide 4 text

ME in Blue !

Slide 5

Slide 5 text

http://qiita.com/HirofumiTamori/items/0dfdbada30c7d8f183fd

Slide 6

Slide 6 text

http://qiita.com/mizchi/items/e38d3f0461fe316021f7

Slide 7

Slide 7 text

Ruby on Rails vs Phoenix Framework

Slide 8

Slide 8 text

Why this theme?

Slide 9

Slide 9 text

! Is an Elixir/Phoenix app appropriate for only middleware or backend service?

Slide 10

Slide 10 text

• Scaffold mix phoenix.gen.html • eex template: erb like template • growing document • WebSocket • Performance • created apps in M3 Hackathon

Slide 11

Slide 11 text

! May Phoenix becomes instead of Rails

Slide 12

Slide 12 text

❓ How to improve my Rails app performance

Slide 13

Slide 13 text

Use Phoenix

Slide 14

Slide 14 text

Agenda • introduction • comparison in development • performance

Slide 15

Slide 15 text

introduction

Slide 16

Slide 16 text

Rails

Slide 17

Slide 17 text

Programmer Happiness sustainable productivity

Slide 18

Slide 18 text

Phoenix

Slide 19

Slide 19 text

Speed Fun development environment

Slide 20

Slide 20 text

Rails ⭐ 26325 1 Phoenix ⭐ 2614 1 1 at 2015/05/31

Slide 21

Slide 21 text

Rails version: 4.2.1 1 Phoenix version: 0.13.1 1 1 at 2015/05/31

Slide 22

Slide 22 text

Compare Phoenix features with Rails supported • WebSocket • Rails 5 plan to include this, but needs Redis

Slide 23

Slide 23 text

Compare Phoenix features with Rails unsupported • Assets pipeline • brunch.io for JavaScript • SQLite adapter • https://github.com/jazzyb/sqlite_ecto

Slide 24

Slide 24 text

Phoenix ≒ Rails + Speed thought

Slide 25

Slide 25 text

Comparison in development

Slide 26

Slide 26 text

• File Structure • Scaffold • Router • Controller • View • Model • Mailer • Assets

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

Scaffold • Rails $ rails g scaffold todo content:text done:boolean • Phoenix $ mix phoenix.gen.html Todo todos content:text done:boolean

Slide 29

Slide 29 text

Router # config/routes.rb resources :todos # web/router.ex resources "/todos", TodoController

Slide 30

Slide 30 text

Named routes: Rails $ rake routes Prefix Verb URI Pattern Controller#Action todos GET /todos(.:format) todos#index POST /todos(.:format) todos#create new_todo GET /todos/new(.:format) todos#new edit_todo GET /todos/:id/edit(.:format) todos#edit todo GET /todos/:id(.:format) todos#show PATCH /todos/:id(.:format) todos#update PUT /todos/:id(.:format) todos#update DELETE /todos/:id(.:format) todos#destroy

Slide 31

Slide 31 text

Named routes: Phoenix $ mix phoenix.routes page_path GET / PhoenixApp.PageController.index/2 todo_path GET /todos PhoenixApp.TodoController.index/2 todo_path GET /todos/:id/edit PhoenixApp.TodoController.edit/2 todo_path GET /todos/new PhoenixApp.TodoController.new/2 todo_path GET /todos/:id PhoenixApp.TodoController.show/2 todo_path POST /todos PhoenixApp.TodoController.create/2 todo_path PATCH /todos/:id PhoenixApp.TodoController.update/2 PUT /todos/:id PhoenixApp.TodoController.update/2 todo_path DELETE /todos/:id PhoenixApp.TodoController.delete/2

Slide 32

Slide 32 text

Controller: index action # app/controllers/todos_controller.rb def index @todos = Todo.all end # web/controllers/todo_controller.ex def index(conn, _params) do todos = Repo.all(Todo) render(conn, "index.html", todos: todos) end

Slide 33

Slide 33 text

Controller: create action in Rails # app/controllers/todos_controller.rb def create @todo = Todo.new(todo_params) if @todo.save redirect_to @todo, notice: 'Todo was successfully created.' else render :new end end

Slide 34

Slide 34 text

Controller: create action in Phoenix # web/controllers/todo_controller.ex def create(conn, %{"todo" => todo_params}) do changeset = Todo.changeset(%Todo{}, todo_params) if changeset.valid? do Repo.insert(changeset) conn |> put_flash(:info, "Todo created successfully.") |> redirect(to: todo_path(conn, :index)) else render(conn, "new.html", changeset: changeset) end end

Slide 35

Slide 35 text

View/Template: collection in Rails <%# app/views/todos/index.html.erb %> <% @todos.each do |todo| %> <%= todo.content %> <%= link_to 'Show', todo %> <% end %>

Slide 36

Slide 36 text

View/Template: collection in Phoenix <%# web/templates/todo/index.html.eex %> <%= for todo <- @todos do %> <%= todo.content %> <%= link "Show", to: todo_path(@conn, :show, todo), class: "btn btn-default btn-xs" %> <% end %>

Slide 37

Slide 37 text

View/Template: partial render <%# *.erb %> <%= render 'form' %> <%# *.eex %> <%= render "form.html", changeset: @changeset, action: todo_path(@conn, :create) %>

Slide 38

Slide 38 text

View/Template: form in Rails <%# *.erb %> <%= form_for(@todo) do |f| %> <% @todo.errors.full_messages.each do |message| %> <%= message %> <% end %> <%= f.label :content %> <%= f.text_area :content %> <%= f.check_box :done %> <%= f.submit %> <% end %>

Slide 39

Slide 39 text

View/Template: form in Phoenix <%# *.eex %> <%= form_for @changeset, @action, fn f -> %> <%= for {attr, message} <- f.errors do %> <%= humanize(attr) %> <%= message %> <% end %> Content <%= textarea f, :content, class: "form-control" %> <%= checkbox f, :done, class: "form-control" %> <%= submit "Submit", class: "btn btn-primary" %> <% end %>

Slide 40

Slide 40 text

Model in Rails # app/models/todo.rb class Todo < ActiveRecord::Base # validations # queries end

Slide 41

Slide 41 text

Model in Phoenix # web/models/todo.ex defmodule PhoenixApp.Todo do use PhoenixApp.Web, :model schema "todos" do field :content, :string field :done, :boolean, default: false timestamps end @required_fields ~w(content done) @optional_fields ~w() def changeset(model, params \\ :empty) do model |> cast(params, @required_fields, @optional_fields) end end

Slide 42

Slide 42 text

in scaffolded controller # Rails @todos = Todo.all # Phoenix todos = Repo.all(Todo)

Slide 43

Slide 43 text

in realworld controller # Rails @todos = Todo.recent(page) # Phoenix todos = Todo.recent(page)

Slide 44

Slide 44 text

Query def self.recent(page) order(created_at: :desc) .offset((page.to_i - 1) * SIZE) .limit(SIZE) end def recent(page) do from(p in Todo, order_by: [desc: p.inserted_at], offset: ^((String.to_integer(page) - 1) * @size), limit: ^@size) |> Repo.all end

Slide 45

Slide 45 text

Mailer • Rails • ActionMailer • Phoenix • not provided • use other libraries such as gen_smtp

Slide 46

Slide 46 text

Assets • Rails • Asset Pipeline • Phoenix • Brunch.io, gulp, etc...

Slide 47

Slide 47 text

Test • Rails • RSpec, Minitest, etc... • Phoenix • ExUnit

Slide 48

Slide 48 text

Ecosystem • Ruby/Rails -> Rubygems • many gems • Elixir/Phoenix -> Hex • few • potential to increse • Hex is easy to use • http://qiita.com/ma2ge/items/0e19bf3f03078f589096

Slide 49

Slide 49 text

Phoenix ≒ Rails development

Slide 50

Slide 50 text

Performance

Slide 51

Slide 51 text

NOTICE ! • Not same template file • On my macbook air • Rough measurement • Using WebRick server for Rails app

Slide 52

Slide 52 text

code # app/controllers/todos_controller.rb def index @todos = Todo.all end # web/controllers/todo_controller.ex def index(conn, _params) do todos = Repo.all(Todo) render(conn, "index.html", todos: todos) end

Slide 53

Slide 53 text

Performance: development $ ab -n 50 localhost:3000/todos # Rails Requests per second: 21.85 [#/sec] (mean) # Phoenix Requests per second: 37.08 [#/sec] (mean)

Slide 54

Slide 54 text

Performance: production $ ab -n 50 localhost:3000/todos # Rails Requests per second: 149.14 [#/sec] (mean) # Phoenix Requests per second: 450.58 [#/sec] (mean)

Slide 55

Slide 55 text

3X faster !

Slide 56

Slide 56 text

Performance: production $ ab -n 500 -c 100 localhost:4000/todos # Rails same as single request mode, because WebRick server # Phoenix Requests per second: 1291.92 [#/sec] (mean)

Slide 57

Slide 57 text

Phoenix > Rails performance

Slide 58

Slide 58 text

Phoenix is Rails like development with Speed

Slide 59

Slide 59 text

Conclusion/IMO • Elixir/Phoenix is not only for middleware but also web application • Phoenix has potential to switch current Rails application • Performance • Targeting developer happiness

Slide 60

Slide 60 text

We're hiring! at.m3.com/job

Slide 61

Slide 61 text

Enjoy

Slide 62

Slide 62 text

Resources: Rails and Phoenix • Ruby on Rails • http://rubyonrails.org/ • https://github.com/rails/rails • Phoenix Framework • http://www.phoenixframework.org/ • https://github.com/phoenixframework/phoenix

Slide 63

Slide 63 text

Resources: Libraries • Awesome Elixir • https://github.com/h4cc/awesome-elixir • PlugRailsCookieSessionStore • Rails compatible Plug session store • https://github.com/cconstantin/ plug_rails_cookie_session_store

Slide 64

Slide 64 text

Resources: Mail Library in Elixir • gen_smtp • https://github.com/Vagabond/gen_smtp • mailman • https://hex.pm/packages/mailman • https://github.com/kamilc/mailman

Slide 65

Slide 65 text

Resources: Ecto • Ecto • https://github.com/elixir-lang/ecto • Composable Queries with Ecto • http://blog.drewolson.org/composable-queries-ecto/ • Ecto vs Active Record • http://learnelixir.com/blog/2014/10/11/ecto-vs-active- record/

Slide 66

Slide 66 text

Resources: Hex • Publishing a package • https://hex.pm/docs/publish • Hex Ͱ Elixir ͷϥΠϒϥϦΛϦϦʔε͢Δํ๏ • http://qiita.com/ma2ge/items/0e19bf3f03078f589096

Slide 67

Slide 67 text

Resources: Performance • Elixir vs Ruby Showdown - Phoenix vs Rails • http://www.littlelines.com/blog/2014/07/08/elixir-vs- ruby-showdown-phoenix-vs-rails/ • Benchmarking Phoenix vs Rails vs Sinatra vs Express vs Martini... • https://github.com/mroth/phoenix-showdown