makoto-developer's テックブログ

私がなぜElixirを選ぶか

10年以上にわたりJava、Go、Python、TypeScriptなど様々な言語で開発を行ってきた。

その中で現在、私が最も積極的に選択しているのがElixirである。なぜElixirを選ぶのか、その理由を技術的な観点から解説する。

Erlang VMの力

ElixirはErlang VM(BEAM)上で動作する。このVMは30年以上にわたり通信システムで使われてきた実績があり、以下の特性を持つ。

軽量プロセスモデル

# 数百万のプロセスを起動可能
Enum.each(1..1_000_000, fn i ->
  spawn(fn ->
    :timer.sleep(10_000)
  end)
end)

Elixirのプロセスは極めて軽量である。数KBのメモリで起動でき、コンテキストスイッチのコストも低い。これにより、OS threadを使う言語では不可能な規模の並行処理を実現できる。

耐障害性

defmodule MyApp.Supervisor do
  use Supervisor

  def start_link(init_arg) do
    Supervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
  end

  def init(_init_arg) do
    children = [
      {MyApp.Worker, []}
    ]

    Supervisor.init(children, strategy: :one_for_one)
  end
end

Supervisorによる監視ツリーにより、プロセスが異常終了しても自動的に再起動される。「失敗を前提とした設計」を言語レベルでサポートしている点が、他の言語にはない強みである。

関数型プログラミングの利点

Elixirは純粋な関数型言語である。イミュータブルなデータ構造により、並行処理時の競合状態を根本から排除できる。

# データは常に新しいコピーを作成
list = [1, 2, 3]
new_list = [0 | list]  # [0, 1, 2, 3]

# 元のリストは不変
IO.inspect(list)  # [1, 2, 3]

これにより、mutexやlockといった複雑な同期機構が不要になる。並行処理のコードが驚くほどシンプルに書ける。

Phoenix Frameworkの生産性

PhoenixはRailsコミッターが作ったフレームワークである。Railsを使ったことがある人はわかると思うが非常に簡単にAPIや画面を作ることができる。

Phoenixは、Elixirの強みを最大限に活用しているのが特徴である。

LiveView - JavaScriptなしのリアルタイムUI

defmodule MyAppWeb.CounterLive do
  use MyAppWeb, :live_view

  def mount(_params, _session, socket) do
    {:ok, assign(socket, :count, 0)}
  end

  def handle_event("increment", _params, socket) do
    {:noreply, update(socket, :count, &(&1 + 1))}
  end
end

LiveViewを使えば、JavaScriptをほとんど書かずにリアルタイムなWebアプリを構築できる。WebSocket通信はフレームワークが自動的に処理する。これは、フロントエンドとバックエンドの境界を曖昧にする革新的なアプローチである。

パフォーマンス

Phoenixは非常に高速である。C10K問題(1万同時接続)どころか、C2M(200万同時接続)を単一サーバーで処理できる実績がある。これはErlang VMの軽量プロセスモデルによる恩恵である。

パターンマッチングの表現力

Elixirのパターンマッチングは、コードを驚くほど読みやすくする。

defmodule Parser do
  def parse({:ok, data}), do: process(data)
  def parse({:error, reason}), do: handle_error(reason)
  def parse(nil), do: {:error, :no_data}
end

条件分岐を関数定義に埋め込むことで、各ケースの処理が明確に分離される。これは、巨大なif-else文やswitch-caseよりも遥かに保守性が高い。

パイプライン演算子

user_id
|> fetch_user()
|> validate()
|> transform()
|> save()

パイプライン演算子により、データ変換の流れを直感的に記述できる。これは関数型プログラミングの「データの流れ」を視覚的に表現する優れた構文である。

エコシステムの成熟

Hexパッケージマネージャーには、高品質なライブラリが揃っている。

  • Ecto - 型安全なデータベースライブラリ
  • ExUnit - 組み込みテストフレームワーク
  • Broadway - データパイプライン構築
  • Oban - バックグラウンドジョブ処理

これらはすべて、Elixirの思想に沿って設計されており、統一感のある開発体験を提供する。

学習曲線

関数型プログラミングの経験がない場合、初期の学習曲線は急である。しかし、一度理解すれば、他の言語よりも遥かに生産性が高い。

特に、並行処理やリアルタイム通信を必要とするシステムでは、Elixirの優位性は圧倒的である。

と言いつつ、通常の手続型言語でも記述でき流。しかも普通に速いので関数型言語を気にしなくても問題なかったりする。

また、Elixirのドキュメントは非常にわかりやすくできていて他の言語も真似してほしいくらいである。この標準関数やビヘイビアはなんだろう?と思ったらドキュメントを読めば大抵理解できる。読み物として読んでいても面白いので楽しい。

Elixir v1.19.5

最新バージョンはこちらから探してみるとよい。

Elixir docs

どんなケースで選ぶべきか

Elixirは以下のような要件に適している。

  • リアルタイム性: チャット、通知、ダッシュボード
  • 高並行性: 大量の同時接続を処理
  • 耐障害性: 24/365運用が求められるシステム
  • データパイプライン: ストリーム処理、ETL

逆に、以下のケースでは他の選択肢も検討すべきである。

  • 機械学習: Pythonのエコシステムが圧倒的
  • システムプログラミング: Rust、C++が適切
  • 既存のJavaエコシステム: 移行コストを考慮

まとめ

Elixirを選ぶ理由は、技術的な優位性だけではない。「失敗を前提とした設計」「並行処理のシンプルさ」「高い生産性」といった、ソフトウェアエンジニアリングの本質的な問題に対する明確な解答を提供している点にある。

10年以上の開発経験を経て、私はElixirが「正しいデフォルト」であると確信している。特に、スタートアップや小規模チームにおいて、限られたリソースで高品質なシステムを構築する場合、Elixirは最良の選択肢の一つであると感じる。