José Valim1さんの2016年5月25日付のブログ記事**Beyond Functional Programming with Elixir and Erlang**の翻訳です。
Joséさんのスタンスにとても共感できたので翻訳しました。
Erlang VMでの関数型プログラミングに少しばかり違った視点を付け足したいと思います:Erlang VMにおいては関数型プログラミングはゴールではありません。単なる手段に過ぎないのです。
Erlang言語及びErlang VMを設計する際、Joe2,Mike3そしてRobert4は関数型プログラミング言語を実装するつもりはなく分散型で耐障害性の高いアプリが作れる実行環境が欲しかっただけです。そのようなシステムを書くためと、関数型プログラミングの原則の多くにたまたま共通のところがあったということです。そしてそれはErlangに、Elixirに反映されています。
ということで最終的なゴールとそのためにどのように関数型プログラミングが助けになりまたそれらのゴールを達成しているかについて問うならば、議論はより面白いものになるでしょう。ゴールについて調べれば調べるほど不変性(immutability)や共有される状態の管理とそれらが強く結びついているかが明らかになっていきます。例えば:
-
耐障害性(Fault-tolerance):ソフト上に2つのエンティティがありそれらがデータの同一の断片について作業していたとして片方がフェイルした(例えば例外を投げた)とします。どうすればフェイルした方のエンティティが壊れた状態を残したままにしないよう保証できるでしょうか。Elixirではこれらのエンティティを「プロセス」と呼ばれる軽量スレッドに隔離でき、状態が共有されてしまわないように保証できます(協調動作は通信によって行われます)。
-
並行性:オブジェクト指向の命令形言語で並行動作するソフトウェアを書く場合多くの問題は共有された可変(mutable)の状態を管理しなければならないことが原因となっています。これらの言語においては(グローバルな名前空間を介しての)共有と可変性はデフォルト動作で、問題が起きたときその原因となっているデータをピンポイントで発見するのがより難しくなります。不変性(immutability)をデフォルトとすることにより、並行動作ソフトウェアを書くときに注意すべき可変部分をより効果的に目立たせることができ、競合状態に取り組む開発者にもっと正確に当たりをつけやすくします。
-
保守性:Erlang、Elixirともにより保守性の高いコードを書く基盤は関数型プログラミングから来ています。不変データは我々が知らないところで変化してしまうということはもうない、ということを保証します!パターンマッチングは簡潔さをもたらし、プロトコルは明確な規約に基づく動的なポリモーフィズムを導入し、などなど…。
上記の例は保守性が高くて堅牢なシステムとしてElixirを紹介する際、私がたいてい好んで使う「理由」です。ところでErlangとElixirには関数型としての意味論に幾ばくかの違いがある(変数再バインド、パイプラインなど)のですが、それにしてもどちらも目的を達成するための手段なのです。振り返って、耐障害性が高い分散型アプリケーションを構築するための基盤はどちらの言語であっても正確に一致します。なぜならどちらも同じVM、同じOTPプラットフォームの上に作られた言語だからです。
関数型的な見方なんか重要ではない、と言ってるわけではありませんよ。というかものすごく重要ですから!私は関数型プログラミングについてよくこんな風にまとめます。それは我々がシステムの複雑な部分を明確にすることを強制するパラダイムであると。そしてそれはソフトウェアを書くにあたってのひとつの重要なガイドラインなのです。幸運にも関数型プログラミングのレッスンの大半はそのまま他の非関数型言語及びプラットフォームに使えるものばかりです。
しかし、他の最終的なゴール(並行性、耐障害性)はそこまで簡単ではありません。並行性は基礎的なレベルから対応されていなければなりません: 実行環境は役に立つような抽象層を提供しなければならず、開発者は実行環境が何をしているかを分析できるよい作業環境やツールを持っている必要があります。耐障害性については、それは局所的なものではないためにアプリの一部として取り扱えないことからより高度な技が必要でしょう。エコシステム全体が同じ原則の上に構築されていないとしたら「鎖の輪の中で最も弱い輪」がいつも切れてしまうことになるでしょう。
もしあなたが24/7で動作し複数のクライアントの要求を受け付けるサービス(ほとんどのネットワークサービスやWebアプリケーションはまさしくこれにあたりますが)を作ろうとしたならば、基礎的なレベルから並行性、堅牢さ、反応性の高さを持ったプラットフォームを選ぶべきです。できる限り多数のユーザーに最高のユーザーエクスペリエンスを与えたいですよね?
もっと重要なことはこれらの関心事は単なるインフラの視点を遥かに超えているということです。開発者はよくパフォーマンスと並行性をアプリケーションのスループット(1秒間に何個のリクエストを捌けるか)に関連付けようとします。しかしながらこれらの機能はプログラマの生産性にもダイレクトに影響するのです。コードのコンパイルが遅いだのアプリケーションの再起動にすごく時間がかかるだのテストスイートが終わるまでに何分もかかるだの、といった事柄はコードを書くのにあたって毎日やっつけないといけない障害になっています。こういう障害はより効率的な実行環境で対処できるはずです。何と言っても、2016年の今、あなたがプログラミング環境でやっていることは全て、マルチコアの全コアを使って実行されるべきなのです。
ここでちょっとした練習問題を:あるCPU性能を非常に必要とするテストスイートを想像してください。それはシングルコアでは実行に2分かかるとします。もしあなたのマシンが4コアならばその実行時間は理想的には30秒になるはずです。全てのテストスイートについてCPU性能だけが効いてくるとは言えないし、完全に並行動作した時の並行度は80%だと仮定してみましょう。だとしてもまだたったの48秒で終わるのです。
強固な基盤はあなたのユーザーに自由自在かつ安定したユーザーエクスペリエンスを楽しむことを保証するばかりではなく、開発者に、より生産的で楽しいイテレーションをも保証します。それがElixirのMixなどのツールがテストを非同期的に実行するだけでなくコードのコンパイルをできる限り高速に、並行に行うことに多大な努力をしている理由です。耐障害性を提供する抽象層は開発者にプロダクション環境についても開発環境についても多くのイントロスペクションを提供します。これらの関心事を念頭に置いて作られているということによりErlangとElixirはそのような(訳註:耐障害性が高く並列かつメンテナンスしやすい)ソフトウェアを書くにあたって多々あるベストなオプションのひとつとなっています。