TeamGenikはElixirとPhoenix LiveViewで作られています
プログラミング言語Elixir
TeamGenikの中核となるシステムは、関数型プログラミング言語であるElixir(エリクサー)で記述されています。
Elixirは、2012年に誕生した新しい言語です。1972年生まれのC、1991年生まれのPython、1995年生まれのJava、Rubyなどと比べると、まだ知名度はありませんが、WebおよびIoTの分野で人気が高まっています。InfoQが2019年10月に発表したProgramming Languages InfoQ Trends Reportは、Elixirが「イノベーター」のフェーズに入ったとしています。
Phoenix Framework
TeamGenikは、ElixirベースのWebアプリケーション開発フレームワークであるPhoenix Framework(「Phoenix」)を採用しています。
Phoenixは、Ruby on Railsから大きな影響を受けています。特に、ルーティングとコントローラの仕組みがよく似ています。Phoenixがデータベース操作のために使用しているライブラリEctoも、Active Recordと類似しています。Ruby on Railsに慣れ親しんでいる私たちにとって、Phoenixはとても自然な選択肢でした。
Phoenix LiveView
TeamGenikは、HTMLコードのレンダリングにPhoenix LiveViewを利用しています。Phoenix LiveViewでは次のような2つの段階を踏んでHTMLコードを生成します。
- アプリの外で発生するイベントを受けてアプリの「状態」を新しい「状態」に変換。
- 「状態」の変化を感知して、HTMLコードを生成。
Phoenix LiveViewは、WebSocketによってブラウザとサーバの間を常時接続します。
Phoenix LiveViewは、「状態」の変化によってHTMLコードに生じた「差分」だけをブラウザに送るので、ブラウザとサーバ間での通信量は低く押さえられます。
シングルページアプリケーション(SPA)開発の新潮流
TeamGenikは、シングルページアプリケーション(SPA)として作られています。すなわち、ユーザーがリンクをクリックするたびに画面遷移を発生させるのではなく、その場で画面の一部を変化させています。
2010年代後半にSPA開発が隆盛となり、React、Angular、Vueに代表されるJavaScriptフレームワークが広く使われるようになりました。
しかし、私たちは2020年代以降の潮流を見据えてPhoenix LiveViewを採用しました。Phoenix LiveViewによるSPA開発は、サーバーサイド中心である点で従来のものと大きく異なります。
上の図は、JavaScriptフレームワークを使ったシステム構成とPhoenix LiveViewを用いたシステム構成を比較したものです。「State」と書かれた2つの楕円は、アプリケーションが保持するデータ(状態)を表します。いずれのシステム構成でもこの「State」からHTMLコードが生成されます。ユーザーによる操作などをきっかけに「State」が変化すると、それに応じてHTMLコードが変化し、ブラウザの画面が変化します。
左のシステム構成では「State」がブラウザ上にあります。この「State」を書き換え、「State」からHTMLコードを生成するために大きなJavaScriptプログラムがブラウザ上で動くことになります。他方、右のPhoenix LiveViewを用いたシステム構成では「State」がサーバーサイドにあります。サーバー上ではElixirプログラムが動いていて、「State」を書き換え、「State」からHTMLコードを生成しています。そして、ブラウザ上で動く小さなJavaScriptプログラムとWebSocketで接続し、ブラウザからのイベントを受け取ったり、HTMLコードの差分をブラウザに送ったりします。
開発の中心がフロントエンド(ブラウザ側)からサーバサイドに移ったことの主な意義は、次の4つです。
- 非関数型言語であるJavaScriptを使ったプログラミングがほぼ不要となる。つまり、システムのほぼ全体を1種類の言語(Elixir)で開発できる。
- フロントエンドからの問い合わせを受けるAPIの実装が不要となる。
- フロントエンドとサーバーサイドで同種の機能(バリデーション等)を重複して作る必要がなくなる。
- 悪意のあるユーザーがJavaScriptのソースコードを解析して、システム攻撃のヒントを得たり、企業秘密を暴いたりできなくなる。
無論、それによって失うものもあります。ユーザーのコンピュータで行っていた処理の一部がサーバーサイドに移ることは、サーバへの負担が増大することを意味します。また、フロントエンドとサーバーサイドの間で発生する通信量が増えます。また、ブラウザとサーバーの間がネットワーク的に離れている場合、ユーザーが反応の遅さを感じる頻度が増えるかもしれません。
私たちは、今後Phoenix LiveViewの開発と受容が進むに従ってこうした欠点は克服されていくだろうと考えています。なにしろ、2019年8月にバージョン0.1が出たばかりで、まだバージョン1.0に達していないのですから。
LiveView Socketはブラウザと1対1に対応する
伝統的なWebシステムでは、少数のWebアプリケーションが非常に多数のブラウザからのアクセスに応答します(下図)。
1つのWebアプリケーションは複数のブラウザからの要求を順番に処理していきます。また、あるブラウザからの要求をどのWebアプリケーションが受け持つかは一定していません。そのため、Webアプリケーションは特定のブラウザ固有のデータを保持することができません。そのデータはデータベースに保存されるか、あるいはブラウザ上の「State」に保存されます。
一方、LiveViewを用いたシステムでは次の図のように、LiveView Socketがブラウザと1対1に対応します。両者はWebSocketを通じて常時接続状態となります。
それぞれのLiveView Socketは極めて小さいため、ひとつのサーバ上で何千個あるいは何万個も動き続けることが可能です。そして、それぞれのLiveView Socketが固有の「State」を保持します。
このように、Phoenix LiveViewを用いるとWebシステムの作り方が根本的に変化します。
LiveView Socketとは何か
プログラミング言語Elixirで書かれたすべてのプログラムは、BEAMという名前の仮想マシン(VM)上で動きます。動いている状態のプログラムはプロセスと呼ばれます。OSレベルのプロセスと区別するために、BEAM上のプロセスは「Erlangプロセス」あるいは「Erlang軽量プロセス」と呼ばれることもあります。もともとBEAMは、プログラミング言語Erlangのために作られたものだからです。
Elixirのプロセスは、別のプロセスを生み出す(spawn)ことができます。すべてのプロセスは互いに隔離され、メッセージの受け渡しを通じて互いに通信します。
Phoenix LiveViewを用いたWebシステムでは、新たなブラウザからの接続要求があるたびに専用のプロセスが生み出されます。これがLiveView Socketです。このプロセスは、ブラウザが接続を切断するまで動き続けます。