この文章はPinterestのエンジニアSteve Cohenさんの2015年12月18日付のブログ記事Introducing new open-source tools for the Elixir communityの翻訳です。
Erlangの作者Joe Armstrongが素晴らしいと褒めていた記事で、PiterestでどのようにElixirが使われているかが分かりました。
高尚な文章なので訳すのに少し苦労しました。誤訳や関連記事などがあればコメント欄にお願いいたします。
80年代は憂鬱で深刻な年代とは典型的に記憶されていない。大衆はワン・チャンの"Everybody have fun tonight"を聴き、デロリアンでできたタイムマシンを夢見ている頃、スウェーデンの電話会社に勤める数人の技術者たちは偶然にも未来を創造した。彼らは遠距離通信の問題の解決をしていた。しかし奇妙な偶然により、彼らが解決しようとしていた問題はデロリアンのタイムマシーンが30年先の未来に移動した後のエンジニアたちが直面していた問題と酷似していた。
その多くの長所にもかかわらず、この魔法のようなシステムは決して多くの人々に支持されることはなかったが、以下のような都市伝説が広まった。経験豊富な技術者たちによって声をひそめて人づてに広まった。君のいとこのルームメイトの彼女が100万ものコネクションを2つのサーバに持っている。君はこんなことが本当に信じられないと思う。
さあ、これからこの物語が真実だったことをお話ししましょう。そして、その結末を。
私はもちろんErlangのことを話しています。そしてErlangがWhatsAppで注目を浴びている一方で、シンタックスにまつわるひどく厄介な遺産を持っていた。勇敢なエリクソンのエンジニアたちは正当な理由があったので、Prologというニッチなコミュニティの外では受け入れられることの決してなかった言語を元に作った。これによりErlangを一目見たプログラマたちは「ひどい見た目だ」や「目が痛い」などという感想を漏らした。さして重大そうには聞こえないが、この理由により長年にわたってErlangは遠ざけられてきた。
いままでは。
Ruby on RailsのコアコミッタのJosé ValimはRailsで並行処理を扱うのに疲れ、Erlangの温かい抱擁を求めて避難した。しかしこれは十分ではなかった、なぜなら人々がどのようにしてシンタックスについての含蓄あるコメントを残して去って行ったのかが分かったからである。勤勉な努力の後の成果は驚くべきものであった。プログラミング言語Elixirの誕生である。ElixirはPythonやRubyプログラマから受け入れられるような、Erlangネイティブと一対一で対応付けられるシンタックスを持つ。それはErlangをはるかに超え、小さくパワフルな言語を提供している。それがPiterestがElixirにワクワクした理由だ。
並列性とエラー処理があることによりElixir(とErlang)はワクワクさせるものを持っている。コンピュータについての驚くべきことの一つに2005年以降速度がさして速くなっていないということがある。起こったことといえばCPUにもっとたくさんのコアを詰め込むことである。一つのプロセッサから複数のプロセッサに変わったのだ。これの問題点はプログラミング言語は複数のコアをとりわけ簡単に有効活用できていないということだ。スレッドを作ることはできるかもしれないが、それを管理し共有状態を扱うのはほんとうにしんどいのである。Elixirの他とは異なる方法とはアクターシステムの内側で動作するということである。アクターシステムは単にいくつかのルールを実装することである。それは以下のようなものである。
- アクターはメールボックスである。
- アクターはイミュータブルなメッセージを送ることで他のアクターたちと通信する。
- メッセージは一度アクターのメールボックスに入る。
- アクターのメールボックスにメッセージが来ると、そのメッセージを引数にコードが実行される。このコードは逐次実行される。
- アクターでエラーが発生した場合はアクター(のプロセス)が死ぬ。アクターは他のアクターを監督する。もし監督されているアクターが死んだ場合、監督するアクターはメッセージを受け取る。もしこのメッセージが処理されなかった場合、この監督しているアクターが死ぬ。
それは十分には聞こえないかもしれないが、これらのルールは並行処理を扱い、エラーから復旧するのをとても簡単にする。Elixirについてあなたにまだ伝えていなかったことの一つに、これは関数型言語でミュータブルなデータ構造を持っていないということが挙げられる。例えばマップというデータ構造(他の言語では連想配列、ハッシュマップなどと呼ばれる※訳者注)があり、ここに一対のキーと値を設定したいとして、その関数を実行するとそのキーと値が設定された新しいマップをその関数は返す。
my_map = HashDict.new
other_map = HashDict.put(my_map, :my_age, 39)
IO.inspect(my_map)
#HashDict<[]> # my_map has not been changed
IO.inspect(other_map)
#HashDict<[my_age: 39]> # other_map has the new values
上記のことからオリジナルのマップは変更されていないということがわかるだろう。この特性により、Erlang VMは処理の実行をコードのどの場所でも止められる。そして未来のどのタイミングでもその止めた場所から再開できる。大半の関数型でない言語ではこれができない。この特性はElixirやErlangがプロセッサをフルに活用することを可能にする。
他のElixirの重要な哲学的な根拠として、ほとんどのエラーは一時的で、悪い状態の蓄積として発生する。これはシステムが動作しているときはいつでも発生しうるものである。なので、(プロセスを)再起動をすると多くの問題が解決する。もしこれがシステムの振る舞いであったらどうだろうか?Elixirがあるので「クラッシュさせる」哲学がもうお分かりでしょう。
アクターは他のアクターをお互いに監視できるので、お互いに再起動もできる。もし問題が起きた場合には、アクターを正常な状態で再起動することができる。これは一時的なエラーを一時的なままにすることができ、エラーを扱うためのたくさんのコードを書く手間を省くという意味でとても重要である。また状態を扱うためのたくさんのコードを書く手間も省く、その代わりにエラーのないコードを書き、何か予想外のことが起きたらアクターをクラッシュさせ焼き払う。これはもちろんひどく単純化させすぎているが、しかしElixirでコードを書くときにはエラー処理のための決まりきったコードが減り、ビジネスロジックにより注力できるだろう。
他にもElixirを愛すべき理由がある。Elixirは優秀な実行時の監視機能がある。リモートコンソールにログインし、問題を突き止め、バックエンドの再起動によって過剰に負荷がかかっていたロギングアプリケーションを再起動することで運用中のシステムの問題をかつて解決したことがある。
Elixirはよく考え抜かれた標準ライブラリを持つ。この言語はパターンマッチングを多用する。これは型のエラーよりもより一般的な値のエラーをチェックするのに役に立つ。またパイプライン演算子という革命的なものもある。これは明瞭で読みやすいやり方でデータをある関数から次の関数に渡せるようになる。パイプラインを理解するために、PythonとElixirのコードを比較してみよう。
python
" ".join(map(str.capitalize, "hello_there_world".split("_")))
elixir
"hello_there_world"
|> String.split("_")
|> Enum.map(&String.capitalize\1)
|> Enum.join(" ")
Pythonの例が全て後ろ向きに進んでいて、内側のコンテクストから外側のコンテクストに向かっているのがお分かりでしょう。それとは対照的にElixirがデータを一つ一つ処理して線形に進んでいる。一つ前のステップの出力が次の関数の第一引数として渡される。このテクニックはUnixのパイプラインに感化されたものだ、素晴らしい。
これまでElixirの素晴らしい機能を見てきた。Pinterest APIと広告APIのリミットを管理するシステムはElixirでできている。そのうちの50%のレスポンスは約500マイクロ秒で返却され、90%は800マイクロ秒で返る。そう、マイクロ秒である。
コードの明瞭性についても見てきた。私たちはJavaでできた通知システムをElixirに置き換えた。Javaのものもアクターを使っていたがコードの量がだいたい10,000行だった。新しいElixirのシステムは約1,000行に減らすことができた。Elixir製のシステムはJava製のものよりも高速で一貫性があり、半数のサーバで運用することができている。
ちょっと待ってくれ。もう少し話したいことがある。
この言語がいかに素晴らしいからといって、私たちはElixirという新しいプログラミング言語を紹介するためだけにこの記事を書いたのではない。私たちはオープンソースを愛するので、Elixirコミュニティにいくつかのコードを寄贈する。私たちは2つのプロジェクトについてお伝えすることにワクワクしている。私たちが重用しているElixometerとRiffedというプロジェクトについてだ。
Elixometer
Elixometerはすでに優秀なExometerという統計情報とロギングのライブラリのラッパーだ。分からないものは直せない。Exometerはコードやそこで取り込まれたライブラリ、そしてErlang VM自体をも可視化することができる。ElixometerはExometerを強化し、Elixirの流儀でロギングや統計情報の収集へのアクセスを提供する。
Riffed
私たちはThrift RPCの重用している。そして悲しいことにElixirのためのThrift実装が存在しない。Erlangのための実装が存在する一方で、色々な理由があるにせよElixirの開発者には優しくない。Riffedはこの問題を解決しつつ、Erlangの実装をElixirのマクロを使って私たちの好む形に大幅に書き換えた。
私たちはElixirにとてもワクワクしている。高度に並行かつ高速でスケーラブルなサーバをElixirで作るのが大好きだ。それと共に私たちはオープンソースの大ファンなので、ここをElixirの良さを見つけるための場所としてみてほしい。もしここを気に入ってくれてErlang VMについての知見があるのでしたら、ぜひ私たちに連絡をください!