「プログラミングElixir」から分散系の世界へ踏み込もう

テストエンジニアしてます、技術部の松尾(@Kazu_cocoa)です。

今回は、2016年8月19日に発売されますプログラミング言語であるElixirの入門書、プログラミングElixir(以下、本書)に関して少し書こうと思います。

プログラミングElixir

プログラミングElixir

私はここ1年以上、Erlang/Elixirを学びながら業務/私事で使っていました。

業務では主にAndroid(Java)/iOS(Objectvie-C/Swift)/Rubyを使っています。その傍、 社内向けWebアプリケーションをElixir x Phoenixフレームワーク を使い構築したり、HTTPリクエストをrecord/play/proxyするテストツールとしてhttp_proxyを実装していたりしました。

f:id:kazucocoa:20160819101724p:plain (社内向けWebアプリケーションのコード分布)

そんな折、翻訳者の笹田さんから恵贈いただきましたので、簡単ですがElixirについてここで書いてみます。

私がElixirを学びはじめたわけ:分散と並行処理

私は、大学の頃にソフトウェアの信頼性や、分散系の問題であるThe Byzantine Generals Problemをかじっていました。そのため、分散系や複雑系に対して技術的な興味を持っていました。また、私は数年前に負荷ツールとしてTsung、XMPP Serverとしてejabberdに出会っていました。(当時はErlangをしっかり使ったわけではありませんが。)

また、数年前からマイクロサービスのような系をサービス開発においても考える必要が出てきました。マイクロサービス時代を乗り越えるために、Rack::VCRでらくらくアプリケーション間テストサービス分割時の複雑性に対処する: テスト戦略の話クックパッドにおける最近のMicroservices事例にあるようなところです。このため、今後何らかのサービス開発するにあたり分散系を対象としたシステムに触れる可能性が高まるであろうと感じていました。

そんな時、分散系や並行処理、信頼性に関する知見をElixir/Erlangから学べそうだと感じたため学んでみることにした、というのがきっかけです。

私のElixir学習の入り口: Programming Elixir

海外ではProgramming Elixirの第1版が2014年10月15日に発売され、その後Elixirのバージョンアップとともに内容に変更が加えられてきました。そして、Elixir1.2をベースにしたものが約2年の時を経て翻訳され、プログラミングElixirとなって世に出てきたことになります。

私の学び始めも、このProgramming Elixirや幾つかの書籍、exercism.ioから始まりました。私は原書を1.0の頃に購入したきりだったので、Elixir1.2で新たに追加された with 構文など、私が読んだことのない内容までが書籍として収まっている状態を見て新鮮さも感じました。

ところで、Elixirは2016年8月19日現在、すでに1.3.2がリリースされ、masterブランチでは1.4系に向けて開発が進んでいます。そのため、幾つかの関数単位では変わっている箇所も見られますが、多くの内容は本書においては問題にならないはずです。

プログラミングElixirについて

本書について

Elixirを学ぶにあたり、基本的な構文の話は当然ながら、Erlang/OTPやマクロ、その周辺のエコシステムの話は避けては通れません。

この書籍は、Elixirの基本的な構文から入り、プロジェクトを作りながらそのエコシステムを学び、OTPとしてGenServerなどの代表的な作り、さらにはマクロまで、ちょうど良い具合に内容が発展しながら話が進んでいきます。

第1部では、変数の束縛の話から始まり、1.2から導入された with 構文に関するまでの構文や構造に関して網羅しています。その中で無名関数や高級関数などの話もされます。再帰表現による繰り返し処理やパターンマッチ、制御フローのような基本的なことがらから、末尾最適化などの話もかじることができます。

第2部では、周辺のエコシステムの話が主になります。mixと呼ばれるビルドツール、ExUnitと呼ばれるテストフレームワークやテストコードがドキュメントになるDocTestsなどです。Elixir1.3からはテストコードに構造を持ち込むためのExUnit.Case.describe/2なんかも加わっているのですが、Elixir1.2では扱われません。このようなところは、若干の差があります。

また、Elixirを用いて mix を使った簡単なプロジェクトを作りながら、Erlang/OTPの資産を学ぶこともできます。その中から、GenServerやTask、Agentはもちろんのこと、スーパーバイザやその木を構成するといった、プロセスの監視/再起動戦略や分散系の構築などの入り口に触れることができます。:observer といった標準のモニタリングツールの話もあります。(ここでいう プロセス は、 ErlangVMにおけるプロセス を意味します。)

ここまで読み進めるとざっとElixirのエコシステム含む全体がどんなものか学ぶことができると思います。また、簡単なライブラリであれば自身で作成し、hex.pmにアップロード・公開することができます。

第3部ではマクロの話やプロトコルによる機能拡張の話など、少し踏み込んだ話になってきます。Lispを学んだことがある人であれば、Elixirのマクロのとある側面では構文に親しみを覚えるかもしれません。私もex_parameterizedという、パラメータ化テストを支援するようなマクロを実装してみました。

このように、本書は大きく3部に分かれています。

こういう人におすすめ

私は英語で学んでいたのですが、本書を読むとやはり日本語訳されているだけあってElixirを理解することに集中することができると感じました。もとの書籍の完成度もさることながら、それが母国語で読めるというのはやはり新しいものを理解する第一歩の手助けとしてとても大きいものがあります。

本書はElixirに興味はあるけれど入り口をどこにおこうか悩んでいる方、Web上で少し学んだけれど理解を整理して腹に落とし込みたい人におすすめします。一方で、この書籍を全くプログラミングに触れたことがない状態で読むには少し難しいかもしれません。

関数型プログラミングを全く知らない状態で読む場合も、少し読み進めるにあたり負荷がかかる場面があるかもしれません。ただ、新しい考え方を学ぶきっかけになるかもしれませんので、読んで損はないかと思います。

Elixirに対してさらに興味を持った人へ

Erlang/Elixirに触れると、"Let it crash"という言葉をよく目にします。これは、処理がクラッシュしたらそのままにしておけ、という意味です。ただ、これは好き勝手にクラッシュさせて良いということではありません。実際は例外をちゃんと考える必要もありますし、プロセスのモニタリングも頭に入れながらプログラムを組む必要があります。また、例外発生時の影響を局所的にするために、スーパーバイザなどを使ったプロセスの設計も考慮する必要があります。

この書籍をざっと学んだ後に、そのようなより発展したことを書籍を使い学びたい場合、以下を参考にすると良いと思います。プロセス間の参照渡しや値のコピー、性能に関すること、Erlang/OTPとの付き合い方などを少し詳しく学ぶことができます。

最後に

簡単ですが、本書の概要や学ぶことができること、さらに学びを深めるために、という形で話をまとめてみました。

初めに書きました私のきっかけであった分散、並行処理への理解は、学び始めの狙い通り深めるきっかけになりました。例えば、並行プロセスとメッセージパッシングによる分散系の構築とそれらを使った処理を実現できること、それらの耐障害性を高めるための仕組みなど。ナインナインの稼働率を実現する、培われたErlangVMとそれらをWebアプリケーションでも活用するElixirの工夫と言ったところです。私個人は、Elixirから入りErlangを学んだことは、プログラミング言語の構文を単に学ぶというよりは、分散系に対する設計レベルで考え方を学ぶことができました。

Elixirは言語としても、そのような分散系の構築や非同期処理を少ない実装で実現できる面白さも経験することができます。本書も日本語で手に取りやすい形になったので是非とも手にとって、案外、分散系も手軽に扱えるものだと体験してみてください。

最後になりますが、本書を翻訳されました笹田さん、鳥井さんには重ねてお礼申し上げます。

プログラミングElixir

プログラミングElixir

/* */ @import "/css/theme/report/report.css"; /* */ /* */ body{ background-image: url('http://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527163350.png'); background-repeat: repeat-x; background-color:transparent; background-attachment: scroll; background-position: left top;} /* */ body{ border-top: 3px solid orange; color: #3c3c3c; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; line-height: 1.8; font-size: 16px; } a { text-decoration: underline; color: #693e1c; } a:hover { color: #80400e; text-decoration: underline; } .entry-title a{ color: rgb(176, 108, 28); cursor: auto; display: inline; font-family: 'Helvetica Neue', Helvetica, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Meiryo, Osaka, 'MS Pゴシック', sans-serif; font-size: 30px; font-weight: bold; height: auto; line-height: 40.5px; text-decoration: underline solid rgb(176, 108, 28); width: auto; line-height: 1.35; } .date a { color: #9b8b6c; font-size: 14px; text-decoration: none; font-weight: normal; } .urllist-title-link { font-size: 14px; } /* Recent Entries */ .recent-entries a{ color: #693e1c; } .recent-entries a:visited { color: #4d2200; text-decoration: none; } .hatena-module-recent-entries li { padding-bottom: 8px; border-bottom-width: 0px; } /*Widget*/ .hatena-module-body li { list-style-type: circle; } .hatena-module-body a{ text-decoration: none; } .hatena-module-body a:hover{ text-decoration: underline; } /* Widget name */ .hatena-module-title, .hatena-module-title a{ color: #b06c1c; margin-top: 20px; margin-bottom: 7px; } /* work frame*/ #container { width: 970px; text-align: center; margin: 0 auto; background: transparent; padding: 0 30px; } #wrapper { float: left; overflow: hidden; width: 660px; } #box2 { width: 240px; float: right; font-size: 14px; word-wrap: break-word; } /*#blog-title-inner{*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-position: left 0px;*/ /*}*/ /*.header-image-only #blog-title-inner {*/ /*background-repeat: no-repeat;*/ /*position: relative;*/ /*height: 200px;*/ /*display: none;*/ /*}*/ /*#blog-title {*/ /*margin-top: 3px;*/ /*height: 125px;*/ /*background-image: url('http://cdn-ak.f.st-hatena.com/images/fotolife/c/cookpadtech/20140527/20140527172848.png');*/ /*background-repeat: no-repeat;*/ /*background-position: left 0px;*/ /*}*/