04 Jul 2014

1 Introduction to Mix

Mixの翻訳をしました。

昨日は先週の続きをしようと思ったら、Elixir Doseというサイトがリニューアルされていて、過去の記事がなくなってしまいました。どのみち先週もMixのことについてはあまり言及されていなかったこともあり、せっかくだから私も翻訳活動をしてみようと思い立ちました。

1 Introduction to Mixです。誤訳等を見つけた場合、GitHubのページにプルリクエストを送信してください。


この章では、スーパーバイザーの連なり(supervision tree)のことや、設定、テストなどを含んだ完璧なElixirのアプリケーションを作る方法について学びます。

アプリケーションは分散型キーバリューストアとして動作します。私たちはこれからキーと値のペアのバケット(単位)と複数のノードにまたがる分散型のバケットを管理します。また、次のようなリクエストを同時に送るノードを複数接続するためのシンプルなクライアントも作成していきます。

CREATE shopping
OK

PUT shopping milk 1
OK

PUT shopping eggs 3
OK

GET shopping milk
1
OK

DELETE shopping eggs
OK

このようなキーバリューアプリケーションを作るのに必要な3つのツールを紹介します。

  • OTPはErlangのライブラリ集です。Erlangの開発者はOTPを使うことで強力で、障害の起きにくいアプリケーションを開発できます。この章ではOTPをElixirで扱ったり、スーパーバイザーの連なりやイベントマネージャーなどを扱います。
  • MixはElixirにおける作成、コンパイル、アプリケーションのテスト、依存関係の管理を扱うためのビルドツールです。
  • ExUnitはElixirをもとに書かれたテスト駆動フレームワークです。

この章では、まずMixを使って最初のプロジェクトを作り進めながら、MixやExUnitとOTPとの違いについて扱います。

注意: この章はElixirのバージョンがv0.14.1以降が必要です。Elixirのバージョンを調べるコマンドはelixir -vで、もし詳しい説明が必要であれば、getting startedの最初の章を読んでください。

1.1 最初のプロジェクト

Elixirをインストールしたら、まずelixirelixirciexの実行ファイルに加えて、Elixirの実行ファイルであるmixを使えるようになります。

まずは最初のプロジェクトをmix newをコマンドラインから実行してみましょう。プロジェクト名を引数に渡して(今回はkv)、そのままであればメインのモジュールは通常Kvというように処理されてしまうので、今回は大文字でKVであることをmixに伝えましょう。

$ mix new kv --module KV

Mixはkvといういくつかのファイルを含んだディレクトリを作成します。

* creating README.md
* creating .gitignore
* creating mix.exs
* creating config
* creating config/config.exs
* creating lib
* creating lib/kv.ex
* creating test
* creating test/test_helper.exs
* creating test/kv_test.exs

生成されたファイルを見てみましょう。

注意: MixはElixirの実行形式のひとつです。mixを実行するのにElixirの実行形式をPATHに含めなければなりません。あるいは、Elixirに直接スクリプトの引数を与えてください。

$ bin/elixir bin/mix new kv --module KV

注意: -Sオプションを指定することで、直接スクリプトを実行することができます。

$ bin/elixir -S mix new kv --module KV

-Sオプションを使うと、ElixirはPATHとスクリプトを探し出し、どこでも実行できるようにしてくれます。

1.2 プロジェクトのコンパイル

mix.exsというファイルは新しいプロジェクトを生成した時に作成され、主な用途はプロジェクトの設定です。さっそく見てみましょう(コメント行は省略しています)。

defmodule KV.Mixfile do
  use Mix.Project

  def project do
    [app: :kv,
     version: "0.0.1",
     deps: deps]
  end

  def application do
    [applications: []]
  end

  defp deps do
    []
  end
end

mix.exsの定義はプロジェクト名やバージョンといったプロジェクトの設定を返すためのprojectと、アプリケーションによってそのまま生成されたapplicationによるふたつの公開関数です。

どちらもdepsという非公開の関数を含んでいて、projectが要求されると依存関係を定義します。本来はdepsを別々のものとして定義する必要はありませんが、プロジェクトの設定を小さくするのに役立っています。

Mixは単純なモジュールの定義を含んだlib/kv.exというファイルを生成します。

defmodule KV do
end

プロジェクトをそのままコンパイルするのに十分です。

$ mix compile

これらは、

Compiled lib/kv.ex
Generated kv.app

lib/kv.exというファイルがkv.appというファイルをコンパイルしました。この.appというファイルはapplication/0という情報が定義されたmix.exsから生成されています。詳細なmix.exsの設定についての機能は後々触れます。

一度プロジェクトがコンパイルされると、プロジェクト内でiexを実行させることができます。

$ iex -S mix

1.3 テストの実行

Mixはプロジェクトをテストするために必要なファイルを自動で用意します。Mixは通常libディレクトリのファイルごとにそれぞれ対応する、testというディレクトリの<ファイル名>_test.exsに沿って実行されます。この規則により、すでにtest/kv_test.exslib/kv.exというファイルが見つかるはずです。しかし、これらはまだうまく結びついていません。

defmodule KVTest do
  use ExUnit.Case

  test "the truth" do
    assert 1 + 1 == 2
  end
end

重要なポイントがふたつあります。

  1. テストが書かれたファイルはElixirのファイル(.exs)なので、テストを実行するたびにファイルをコンパイルする必要がありません。
  2. ExUnit.CaseをテストのAPIに組み込んだり、test/2という単純なマクロを定義するためにKVTestと呼ばれるテストモジュールを定義しました。

Mixはtest/test_helper.exsという素早くテストフレームワークのセットアップさせるファイルも生成しています。

ExUnit.start

このファイルは毎回テストを実行するごとに自動的にMixに呼び出されます。テストの実行はmix testです。

Compiled lib/kv.ex
Generated kv.app
.

Finished in 0.04 seconds (0.04s on load, 0.00s on tests)
1 tests, 0 failures

Randomized with seed 540224

mix testを実行すると、Mixはソースファイルをコンパイルして、アプリケーションを生成し直してくれます。これはMixが次の章で説明する複数の環境を使い分けているからです。

そのうえ、ExUnitはテストの結果を成功はピリオドで表示して、ランダムな値をシードに表示していることがわかります。目的にあわせてテストに失敗して、何が起こるか確かめましょう。

test/kv_test.exsのアサーションを書き換えてください。

assert 1 + 1 == 3

mix testを再び実行します(二回目以降はコンパイルされません)

1) test the truth (KVTest)
   test/kv_test.exs:4
   Assertion with == failed
   code: 1 + 1 == 3
   lhs:  2
   rhs:  3
   stacktrace:
     test/kv_test.exs:5

Finished in 0.05 seconds (0.05s on load, 0.00s on tests)
1 tests, 1 failures

アサーションの失敗ごとにExUnitは詳細な結果と、テストケースの名前と左手側(lfs)に失敗した値と右手側(rfs)に==オペレーターを表示しています。

2行目の失敗は、テストそのもののファイル名で、テストがどこに定義されているかを示しています。もし、2行目をそのままコピーして、mix textのあとにペーストすると、Mixは直接そのテストの箇所を部分的に実行します。

$ mix test test/kv_test.exs:4

このショートカットはプロジェクトの開発を進めるにあたり、該当箇所のテストだけを実行しながら修正することができるのでとても便利です。

最後に、スタックトレースは与えられたテストの情報をもとに、ソースの失敗部分を部分的に実行し、失敗した原因を関連づけます。

1.4 環境

Mixには"環境"という概念があります。これは開発者が特定の状況に応じた拡張を可能にします。標準では、Mixは3つの環境が存在しています。

  • :dev - Mixが標準で実行するタスク(例: compile)
  • :test - mix testで使われる
  • :prod - プロダクションに一度だけ実行される

注意: プロジェクトにそれぞれの環境に対して依存するライブラリを加える場合、これらは自動で引き継がれることはありません。ただし、:prodは環境の設定を引き継ぎます。

標準で、これらの3つの環境はすべて同じ設定で動作します。環境ごとの個別設定を行う必要がある場合はMix.envの機能を参考に、mix.exsがそれぞれの環境をatomで返します。

def project do
  [deps_path: deps_path(Mix.env)]
end

defp deps_path(:prod), do: "prod_deps"
defp deps_path(_), do: "deps"

Mixは標準で:dev、テストのタスクを実行するための:testを使用します。環境はMIX_ENVの環境変数をもとに変更できます。

$ MIX_ENV=prod mix compile

1.5 詳細

プロジェクトの開発に詳細なMixの情報が必要であれば、いつでもヘルプタスクを開いて、実行可能なすべてのタスクのリストを取得することができます。

$ mix help

そして、タスクごとの詳細な内容を知るにはmix help タスク名を実行します。

さあ、コードを書きましょう。