Playing with Phoenix Framework — Rails’ younger brother
Have you heard about Phoenix? It’s a new web framework written in Elixir language. And Elixir itself is a Ruby inspired language that runs on Erlang Virtual Machine. Yes, a lot of ties and references, but we are all one big family here, aren’t we?
Let’s see how closely related are Phoenix and Rails. We’ll do it all from scratch on OS X, with some help from Homebrew package manager.
The Environment
We’ll start with installing both languages that the frameworks rely on. Just like Ruby, Elixir already has several version managers to choose from, like exenv and kiex. But we won’t use them for the sake of simplicity.
Ruby installation:
$ brew install ruby
Elixir installation:
$ brew install elixir
Next thing we need is a package manager. Just like Ruby has its Gems
, Elixir’s package manager is called Hex
. Equivalent for Ruby’s Rake
is Elixir’s Mix
. Hex + Mix
combined give us Ruby’s Bundler
dependencies management functionality.
So we use Mix task to install Hex package manager:
$ mix local.hex
The Foundation
We don’t do it often, so let’s recall how to install the Rails framework:
$ gem install rails
Phoenix framework installation is no harder:
$ mix archive install phoenix
We’re ready to create a new application. In Rails it’s nothing more than running everyone’s most beloved command:
$ rails new railsapp
The command created new app with its directory structure, and then Bundler downloaded and installed all dependencies.
Let’s see how Phoenix deals with the task:
$ mix phoenix.new phoenixapp
Wow! New application created, dependencies downloaded. Beautiful.
To test our sample application we have to start a web server.
A Rails server:
$ rails server
And Phoenix server:
$ mix phoenix.server
GET /hello_phoenix
Both frameworks are MVC based, so our main building blocks are models
, views
and controllers
. Just like Rails, Phoenix has generators for those:
$ rails generate model
vs.
$ mix phoenix.gen.model
…but this is the easy way. I want to compare how to add the base features by hand, just to figure out the differences.
We’ll create sample page displaying a welcome message.
First things first, we’ll add a route for it. With Rails, we create new route by editing config/routes.rb
file:
Rails.application.routes.draw do
get '/hello' => 'hello#index'
end
In Phoenix we have web/router.ex
:
defmodule Phoenixapp.Router do
use Phoenixapp.Web, :router
...
scope "/", Phoenixapp do
pipe_through :browser # Use the default browser stack
get "/hello", HelloController, :index
end
end
Now, controllers time!
Within Rails app create app/controllers/hello_controller.rb
file:
class HelloController < ApplicationController
def index
@text = 'Hello from Controller'
end
end
Within Phoenix create web/controllers/hello_controller.ex
file:
defmodule Phoenixapp.HelloController do
use Phoenixapp.Web, :controllerdef index(conn, _params) do
conn |> render "index.html", text: "Hello from Controller"
end
end
For the view we’ll use Rails’ erb
and Elixir’s equivalent: eex
.
For Rails we only need to create one file: app/views/hello/index.html.erb
<h1><%= @text %></h1>
Phoenix requires us to create a view module beside the template. It’s (more or less) like a view helper in Rails. It will sit in web/views/hello_view.ex
:
defmodule Phoenixapp.HelloView do
use Phoenixapp.Web, :view
end
The accompanying template file will be web/templates/hello/index.html.eex
:
<h1><%= @text %></h1>
Run servers once again. Go to the browser, type http://localhost:3000/hello
for Rails and http://localhost:4000/hello
for Phoenix. It just works! Do you have this feeling again?
Rising from the ashes
Who doesn’t like benchmarks and numbers? So here they are. Rails app was benchmarked with Passenger in production
environment. Phoenix app was running with built-in cowboy server. The machine was Macbook Pro (2014, 2.6GHz i5, 8GB RAM).
Rails:
$ passenger start -e production
$ wrk -c100 -d10s http://localhost:3000/hello/Running 10s test @ http://localhost:3000/hello/
2 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 143.47ms 21.31ms 295.32ms 91.25%
Req/Sec 346.55 39.50 440.00 74.50%
6927 requests in 10.05s, 8.96MB read
Requests/sec: 689.55
Transfer/sec: 0.89MB
Phoenix:
$ MIX_ENV=prod mix compile.protocols
$ MIX_ENV=prod PORT=4001 elixir -pa _build/prod/consolidated -S mix phoenix.server
$ wrk -c100 -d10s http://localhost:4001/hello/Running 10s test @ http://localhost:4001/hello/
2 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 16.73ms 3.78ms 78.27ms 91.46%
Req/Sec 3.02k 290.98 3.58k 83.00%
60097 requests in 10.01s, 72.67MB read
Requests/sec: 6003.29
Transfer/sec: 7.26MB
Note that it is just a simple benchmark with empty controller. You have been warned :)
Oh, there is one important thing. Phoenix is Elixir, and Elixir is not Ruby. It looks a lot like Ruby but there are differences.
What else? In both frameworks’ controllers
we have a params
hash to manage url params. Error pages are very similar. There are more equalities. Asking for models? Rails has ActiveRecord, Phoenix has ecto. Both support various database drivers, tasks for managing the database and its schema through migrations. Both frameworks ship with built-in testing frameworks.
If you know Rails, you already are familiar with Phoenix. It is still very young, so you have the chance to be an early adopter, and I highly encourage you to play with it while it’s hot!