[翻訳] Railsの弟、Phoenix Frameworkで遊ぼう

  • 131
    Like
  • 0
    Comment
More than 1 year has passed since last update.

Michał Kalbarczykさんの2015年7月28日付のブログ記事Playing with Phoenix Framework – Rails’ younger brotherの翻訳です。
Elixirはよく「Erlangの文法をRuby風にしたもの」と言われますし、開発者のJosé ValimさんがRailsの開発コアメンバーであることからか開発環境もRubyをお手本にしたものが多いです。
この記事はPhoenix FrameworkについてRuby及びRuby on Railsといろいろ比較しながら書かれています。

Phoenixについての復習も兼ねて訳してみました。


phoenix_blogpost.jpg

Phoenixについて聞いたことはありますか?Elixir言語で書かれた新しいWebフレームワークです。Elixirはそれ自体がRubyにインスパイアされておりErlang仮想マシン上で動作します。そう、そこにはたくさんの繋がりや相互の参照があるわけで、いわば大きな家族がいるようなものですよ。ね?

ではPhoenixRailsがどのぐらい密接に関連しているか見てみましょう。その作業はOS Xの上でいくらかHomebrewパッケージマネージャの助けを借りてスクラッチから行うこととします。

環境を作る

ではまず両フレームワークが依存する言語のインストールから始めましょう。Rubyと同様にElixirにも既にバージョン管理ツールの選択肢がいくつかあります。例えばexenvkiexなどが。しかしここでは話を簡単にするためそれらは使いません。

Rubyのインストール1:

$ brew install ruby

Elixirのインストール:

$ brew install elixir

次に必要なのはパッケージマネージャです。RubyがGemsを持っているようにElixirのパッケージマネージャはHexと呼ばれています。RubyのRakeに相当するのはElixirではMixです。Hex+Mixは合体技でRubyのBundlerの依存性管理機能を持ちます。

ではMixのタスクでHexパッケージマネージャをインストールしましょう:

$ mix local.hex

基礎的なお話

めったにすることじゃないのでRailsフレームワークをどうやってインストールしたか思い出してみましょう:

$ gem install rails

Phoenixフレームワークについても特に難しくはありません:

$ mix archive install phoenix

これで新しいアプリケーションを作成する準備が整いました。Railsではみんな大好きなこのコマンドを実行するだけです:

$ rails new railsapp

このコマンドで新しいアプリケーションがディレクトリ構成とともに生成されBundlerが依存関係のあるものをダウンロードしてインストールします。

ではPhoenixではこの作業をどのように扱うのでしょうか:

$ mix phoenix.new phoenixapp

おお、新しいアプリケーションが生成されて依存関係ファイルがダウンロードされたじゃないですか。美しい!2

サンプルアプリケーションをテストするにはWebサーバーを起動するしなければいけません。

Railsのサーバーは:

$ rails server

そしてPhoenixのサーバーは:

$ mix phoenix.server

で起動します。3

GET /hello_phoenix

両フレームワークはともにMVCベースなので主なビルディングブロックはモデルビュー,コントローラとなります。Railsと同じく、Phoenixもこれらのジェネレータを持っています。

$ rails generate model

に対して

$ mix phoenix.gen.model

ですね。しかし、これはお手軽なやり方です。私としては違いをはっきりさせるために基本的な機能を手動で追加するやり方を比較したいわけです。

ではウェルカムメッセージを表示するサンプルページを作ってみましょう。

最初に行うのはルーティングの追加です。Railsの場合、新しいルートを生成するにはconfig/routes.rbファイルの編集を行います:

Rails.application.routes.draw do
  get '/hello' => 'hello#index'
end

Phoenixでは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

次はコントローラです。

Railsアプリではapp/controllers/hello_controller.rbファイルを生成します:

class HelloController < ApplicationController
  def index
    @text = 'Hello from Controller'
  end
end

Phoenixではweb/controllers/hello_controller.exファイルを生成します:

defmodule Phoenixapp.HelloController do
  use Phoenixapp.Web, :controller

  def index(conn, _params) do
    conn |> render "index.html", text: "Hello from Controller"
  end
end

ビューについてはRailsではerbをPhoenixでは相当品のeexを使います。

Railsの場合はただひとつapp/views/hello/index.html.erbが必要なだけです:

<h1><%= @text %></h1>

Phoenixはビューのテンプレートだけではなくモジュールも必要になります。それは(多かれ少なかれ)Railsのビューヘルパーのようなものです。場所はweb/views/hello_view.exです:

defmodule Phoenixapp.HelloView do
  use Phoenixapp.Web, :view
end

関連するテンプレートファイルはweb/templates/hello/index.html.eexです:

<h1><%= @text %></h1>

ではサーバーをもう一度起動して、ブラウザで
Railsにはhttp://localhost:3000/hello
Phoenixにはhttp://localhost:4000/helloとタイプしてみましょう。動きますね!この感じまた味わいたいですか :laughing:

灰の中から舞い上がる

ベンチマークや数値に興味のない人っていますかね?ということでベンチマークを。
RailsアプリはPassengerを使ってProduction環境で行いました。Phoenixは組み込みのcowboyサーバーで走っています。実行環境は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:4

$ 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

単純なベンチマークを中身が空に等しいコントローラに対してやった、という点には注意してください。と今、警告したからね :laughing:

ここで重要な事を。PhoenixはElixirで走ります。ElixirはRubyではありません。Rubyにとっても似ていますが違いがあります。

他に何が?どちらのフレームワークのコントローラparamsハッシュをURLパラメータの管理用に持っています。エラーページはそっくりです。他にもたくさんの同等な点があります。モデルについて知りたい?RailsはActiveRecordを持っており同様にPhoenixにはectoがあります。どちらも様々な5データベースドライバーを持っていますしデータベースとそのスキーマをマイグレーションを通じて管理する機能があります。どちらのフレームワークにもテストフレームワークがあります。

もしあなたがRailsを知っていれば、Phoenixについても既に慣れていると言ってもいいでしょう。Phoenixはまだ出来たてです。ですからあなたにもアーリーアダプターになれるワンチャンありますよ。さあ、熱々のうちに遊んでみよう!


  1. 雑談:永らくメインの生活マシンがWindows(+cygwin)でサーバー系がLinux(Kernel 1.3.xあたりからお世話になっています)という作業環境だったのですが昨年から公私ともにMacも使うようになりました。それまで外部の勉強会に出てみるとMac持ってきてる人ばかりなんで「このノマド気取りめ(w)」とか思ってたんですがhomebrewを使ってみてその理由が分かりました。brew install一発でなんでも入っちゃうんだからこれは楽。 

  2. 翻訳時に原文のノリにどこまで付き合うかは常に悩みどころです(笑) 

  3. 正確にはどちらもこの前にアプリケーションのディレクトリにchdirする必要がありますね。なお、phoenixサーバーはデフォルトではポート番号4000で起動します。 

  4. 本文に書いてないですがproduction環境で何故かポート4001番で実行していますね。 

  5. 現時点でectoはデフォルトのデータベースとしてPostgresqlに、あとMySQL(MariaDB)とSqlite3に対応しています。なのでPhoenixを動かして何かデータを記録させるためにはPostgresqlが既にインストールされて適当に設定されている必要があります。今回の例では不要ですが。