ZEAM開発ログ2018ふりかえり第1巻(黎明編): 2017年秋の出会いから2018年2月にElixirを始めるに至った経緯について

(この記事は[「技術的ポエム Advent Calendar 2018」](https://qiita.com/advent-calendar/2018/poem)の1日目です)

ZACKY こと山崎進です。

2018年ももう12月です。ついにアドベントカレンダーの季節がやってまいりました。[「技術的ポエム Advent Calendar 2018」](https://qiita.com/advent-calendar/2018/poem)にお邪魔して，私のElixir研究開発についてふりかえって技術的ポエムを書いてみたいと思います。

# ことの発端〜2017年9月 piacere_ex さんとの出会い

時は2017年9月29日，ひびきのAI社会実装研究会に参加したことで @piacere_ex さんと出会ったことがきっかけでした。会の中でもディスカッションで盛り上がったのですが，会が終わった後に2時間以上にわたって話が盛り上がったのでした。

最初の方はお互いの自己紹介からのコンピュータ遍歴の話で盛り上がりました。 @piacere_ex さんと私で，学生の頃までの経歴がかなり似ていたんですよね。小学校の頃からプログラミングに明け暮れていたとか，機械語やアセンブリ言語でのゲームプログラミングに興じていたとか，学生時代にOSやプログラミング言語処理系の研究をしていたとか。

そういう話になって，私が2016年に研究・開発したZackernel(ザッカーネル)を紹介したんでした。これは，2016年当時に組込みソフトウェアプログラミング演習の授業でキッチンタイマの開発を指導していた時に，学生に入り混じって教師である私自らも開発をしたくなり，今まで作ったことがない方式で作ってみようとチャレンジして作ったものでした。

Node.js で採用されている Node プログラミングモデルというものがあります。こんな感じのコードです。

```javascript
const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('Hello World\n');
});

server.listen(port, hostname, () => {
    console.log(
        'Server running at http://${hostname}:${port}/'
    );
});
```

上記のコードは，Node.js によるウェブサーバーのサンプルプログラムです。このウェブサーバーのプログラムを実行して，ウェブブラウザで http://localhost:3000 にアクセスすると Hello World と表示されます。このウェブサーバーに接続があるごとに，`(req, res) => {...}` で示されるコールバック関数が呼び出されます。この際にスレッドを生成してスタック領域を確保するようなことはしません。

Nodeプログラミングモデルの利点について説明します。

例えばウェブサーバーで広く普及している Apache は，マルチタスクを実現する方式としてマルチスレッド方式/マルチプロセス方式を採用しています。この方式だと1つ1つのタスクに対しスタックメモリを確保します。そのため，Apache では1コネクションあたり数十MBものメモリを消費すると言われています。料理に例えると，マルチスレッド方式・マルチプロセス方式は何人ものコックを動員して1人1人がそれぞれ1つの料理を作る方式です。調理場がコックで溢れかえってしまうので，並行して調理できる料理数が限られるということがわかるかと思います。

![マルチスレッド方式/マルチプロセス方式](https://qiita-image-store.s3.amazonaws.com/0/55223/96d73ce6-2b6f-d275-9d20-95b143d6136f.jpeg)

これに対し，Nodeプログラミングモデルで採用しているコールバック方式では，1つのスレッド/プロセスで並行処理を実現します。料理で例えるなら，料理人1人で伝票を見ながらいくつもの料理を調理するという方式です。これにより，スタックメモリを大きく消費せずに，マルチタスクを実現できます。

![コールバック方式](https://qiita-image-store.s3.amazonaws.com/0/55223/5e557b8a-641c-f3e3-cc78-59ca8ddfaf33.jpeg)

その代わり，1つ1つのコールバックタスクは短時間に待ちなく確実に完了する必要があります。もし長時間の実行になったり待ちが発生したりした場合には，全体のスケジューリングが停止してしまいます。

私はNodeプログラミングモデルをマルチタスクの仕組みとしてとても斬新だと思っています。同じ方式でC言語やC++で実装できたとしたら，軽量なマルチタスクの仕組み，マイクロカーネルができると思いました。そこで，Zackernel ではNodeプログラミングモデルを採用してC++でマルチタスクのマイクロカーネルを実装してみたのです。C言語ではなくC++を採用したのは，Nodeプログラミングモデルに不可欠なラムダ式をC++11から言語処理系レベルでサポートしていたからでした。

Zackernel のコードは次のような感じです。全体として，`TIC` ミリ秒おきにLED1を点灯したり消灯したりする処理を行います。

```c++
void blinkLed1() {
  zLoop([&] {
    digitalWrite(LED1, HIGH);
    sleep(TIC, [&] {
       digitalWrite(LED1, LOW);
       sleep(TIC, [&] {});
    });
  });
}
```

Arduino に準拠したコードになっています。`digitalWrite(LED1, HIGH)` は LED1 を点灯し，`digitalWrite(LED1, LOW)`は消灯すると思ってください。

`[&] {...}` は C++11 で採用されたラムダ式(無名関数)です。実際にはブロックの部分が独立した関数になります。したがって次のようなコードと等価です。

```c++
void blonkLed1_3() {
}

void blinkLed1_2() {
 digitalWrite(LED1, LOW);
 sleep(TIC, blinkLed1_3());
}

void blinkLed1_1() {
  digitalWrite(LED1, HIGH);
  sleep(TIC, blinkLed1_2());
}

void blinkLed1() {
  zLoop(blinkLed1_1());
}
```

ここで登場する Zackernel で提供するサービスは次の通りです。

* `zLoop`は引数で与えられた関数を何回も繰り返し呼び出します。
* `sleep`は第1引数で与えられた時間スリープした後，第2引数で与えられた関数を呼び出します。

Zackernel の実装はとても苦労しました。バグが取れず，3回基本設計からやり直すことになりました。基礎部分が完成したものの，他の仕事が忙しくなって，ずっと放置する羽目になりました。

この辺りの話を @piacere_ex さんにしたところ，いたく気に入ってくださったのでした。

このときにも @piacere_ex さんから Elixir へのお誘いは受けていました。面白いとは思ったものの，当時私は Julia に関心がありました。その当時から Python では数値計算の処理能力が追いつかないことを問題意識として持っていて，有力視していたのが Julia でした。 @piacere_ex さんに Julia の話をしたところ，「Julia も良いですね」というようなコメントを笑顔でもらいました。そのときには Elixir については，それっきりでした。

その後しばらくメールのやり取りが続き，盛り上がり続けました。技術の話でこんなに盛り上がったのは久しぶりのことでした。

当時の私の研究の関心事は，教育や地域課題の解決など，社会的なことの方に関心が強く，純粋な技術についてはどちらかと言えば枯れた技術を使う方でした。

ただ折からのAIブームの到来を見ていて，いよいよAIが社会実装に使えるようになったなと思うようになったのと，同僚に永原正章先生という頼もしいAIの専門家が加わっていろいろと教わるようになったことを受けて，ひびきのAI社会実装研究会にも参加し，AIの社会実装について研究をしだしたという状況で，少し自分の研究の節目だなと自覚するようになってきた頃でした。

そのときに @piacere_ex さんと出会って純粋に技術の話で盛り上がって，「ああ，そうそう，技術の追求って，面白いものだったんだよな」と思い返すようになったのでした。

# 同時期のできごと: ライフ・シフト〜秘密基地ファシリテーターブートキャンプ

「自分の研究の節目」ということについて，より詳しく書きます。

きっかけの1つは[「ライフ・シフト(LIFE SHIFT)」](https://amzn.to/2QALUEg)という本を読んだことでした。この本を手に取った理由も，自分の方向性になんとなく行き詰まりを感じていたからでした。この本の主題は，とくに私の世代，第2次ベビーブーマーは，1本道のライフステージを生きているのでは全く立ち行かないことを詳細で精緻な定量的シミュレーションをいくつも提示して，これでもかと描いた後，ライフステージを何段にも「シフト」することで，どうにか100歳人生時代を生き延びることができる，ということです。

私は[「ライフ・シフト」]((https://amzn.to/2QALUEg))を読んだことをきっかけに，自分の将来について改めて真剣に考えました。諸事情で私には財政的な蓄えがあまりないことと，大学教員という仕事には必ず定年があるということから，定年後も何か仕事を持って働き続けるということについては，すでに決意していました。しかし[「ライフ・シフト」]((https://amzn.to/2QALUEg))が指摘してきたのは，定年後にも通用する専門性を今の段階で新たに獲得すべきだということでした。我が身をふりかえってみたときに，今，主力にしている「教育」の研究は，定年を迎えて大学の教職から解き放たれた時に「大学」という定常的な教育の実践の場を失うことになるので，とても脆弱であるということに気づいたのです。

そういう問題意識を抱えた状態で，2017年9月30日〜10月1日に北九州市小倉の秘密基地で開催された，渋谷健さんの主催するファシリテーターブートキャンプに参加しました。とても濃厚なブートキャンプで，詳細には書ききらないのですが，実に多くのことを得ました。

特に，[「ライフ・シフト」]((https://amzn.to/2QALUEg))で突きつけられた問いに対して，ファシリテーターブートキャンプである程度の答えが得られました。

それは**「自分の今のやりたいことを突き詰めていけば，自ずと定年後を切り拓く道が見えてくる」「自分の直観を信じよ」**ということでした。

こういう背景で，2017年当時は「今が自分の研究に関する転換点である」という意識のもとで動いていました。

# 2018年2月 Elixir と fukuoka.ex との出会い

その後， @piacere_ex さんとはメールを何回かやりとりして盛り上がっていたのですが，11月から12月くらいにはお互いに忙しくなってメールが途絶えていました。しかし，その後 @piacere_ex さんから連絡がきて「福岡 x 人工知能で登壇してほしい」という依頼がきました。その結果，[第4回 福岡×人工知能×「育て方」](https://techjin.connpass.com/event/76616/)にて，「人工知能の育て方」というような講演をします。

[![AI Talk 人工知能の育て方 スモールスタート，ソフトウェア品質保証，教育工学の考え方に沿って](https://qiita-image-store.s3.amazonaws.com/0/55223/744e11d7-902b-ae90-5bd4-d560ce63a708.png)](https://zacky1972.github.io/AI-talk-how-to-grow/#/)

これでまた急速に盛り上がり，再び Elixir について思い出す機会に恵まれました。今度は私も興味を持つようになり「Elixir で何か一緒にやりましょう」という話になりました。「私は何をやりましょうか？」と @piacere_ex さんに尋ねたところ，Zackernel のことを覚えてくださっていて，「じゃあ Elixir の処理系である Erlang VM について研究を進めましょう」という話になりました。

それで2018年2月になって Elixir を初めてインストールして勉強しだして，2018年2月23日の[fukuoka.ex #5](https://techjin.connpass.com/event/79311/)で登壇することになりました。Elixirを勉強し始めてわずか2週間足らずの出来事です！

[![fukuoka.ex ZEAM開発ログ 第1回: BEAMバイトコード・インサイド〜30年の歴史を誇るBEAMを超えるには](https://qiita-image-store.s3.amazonaws.com/0/55223/318b55bb-4b36-45ee-c9b9-b1ae7b80e55e.png)](https://zeam-vm.github.io/zeam-fukuoka.ex-20170223/#/)

前半は，バイトコードの解析がうまく進まなかった言い訳wをしています。後半は，ZEAM構想について語っています。2018年末の現在となっては，だいぶ様相が変わりました。現在の構想については，稿を改めてご紹介します！

# まとめに代えて〜セレンディピティについて

Elixir の研究を進めていくうちに，昔，学生時代に研究していたプログラミング言語処理系のテーマを懐かしく思い出すようになりました。学生の時に最初に自ら「やりたい！」と心底思った研究テーマというのは，ほかの研究テーマにはない，情熱的なアイデアが次から次へと湧き出るものなのだなと痛感しました。様々な研究テーマを変遷して，今，このテーマに戻ったことについては，大いに意味があることだろうと思っています。

2017年秋に遭遇した数々の出会いが，このように結果的に研究人生において大きな転換点になりました。**セレンディピティ**(serendipity)という言葉がありますが，まさにセレンディピティという言葉が当てはまるようなことでした。

この例に限らず，私の身の回りではセレンディピティが良く起こります。なぜ私の身の回りでセレンディピティが良く起こるのかということをふりかえると，2つのポイントがあるように思います。

1つは，**常に問題意識を持つこと**だと思います。もし問題意識を持たず漫然と時を過ごしていたとしたら，セレンディピティが引き寄せてきた「偶然」の重要性に気づくことなく，日常に埋没してしまっていたことだと思います。私の場合は「研究の方向性が今のままで良いのか」「100年人生で追い求めるテーマは何か？」という問題意識を持ち続けていました。そのため，Elixirが目の前に現れた時に「これこそが追い求めていたテーマだ！」ということに気づけたのだと思います。

もう1つは，**人のことを信頼していること**だと思います。人のことを信頼できたからこそ，初対面でも意気投合して深い話ができたのだと思います。人がもたらしてくれた話に真摯に耳を傾け，自分の内面のテーマと呼応させること。それこそが，セレンディピティを次々と生み出すのに必要な姿勢なのではないでしょうか。

みなさんがそういう人生を変えるようなセレンディピティと出会えますように，ということを祈念して，「ZEAM開発ログ2018ふりかえり第1巻(黎明編): 2017年秋の出会いから2018年2月にElixirを始めるに至った経緯について」を終えたいと思います。ありがとうございました！

実は，本日はもう1本アドベントカレンダーの記事を書いています。[「fukuoka.ex Elixir／Phoenix Advent Calendar 2018」](https://qiita.com/advent-calendar/2018/fukuokaex)の1日目[「ZEAM開発ログ2018年総集編その1: Elixir 研究構想についてふりかえる(前編)」](https://qiita.com/zacky1972/items/c9865f59259303d5f53e)という記事です。もしよかったら，こちらもご覧ください。

また明日もアドベントカレンダーの記事を書きます。[「言語実装 Advent Calendar 2018」](https://qiita.com/advent-calendar/2018/lang_dev)の2日目，[「ZEAM開発ログ: Elixir マクロ + LLVM で超並列プログラミング処理系を研究開発中」](https://qiita.com/zacky1972/items/cc88260a3c93c9f71317)という記事の予定です。どうぞお楽しみに！

もしよかったら他の[「ZEAM開発ログ」](https://qiita.com/zacky1972/items/70593ab2b70d192813df)もお読みください。

[「技術的ポエム Advent Calendar 2018」](https://qiita.com/advent-calendar/2018/poem)の明日2日目の記事は， @taptappun さんの「Hello WorldができたWebエンジニアの皆様へ。次はCRUDを目指してみよう！」です。こちらもお楽しみに！