WEBASSEMBLY - What's the right thing to write?

# WEBASSEMBLY - What's the right thing to write? -

[![thumbnail](https://image.slidesharecdn.com/slide-230525010716-1ea127c8/85/slide-1-638.jpg
)](https://www.slideshare.net/shinyoshida982/webassembly-whats-the-right-thing-to-write-258006407)

この記事は WebAssembly の社内勉強会の資料と、その日本語訳です。

なお、表題の元ネタはハーバード大学のサンデル先生が書いた「これから正義の話をしよう」という本の原題「JUSTICE - What's the right thing to do?」です。
(プログラマーはコードを write する。 right と write で韻を踏んでると思いました。)

## イントロダクション

WebAssembly とは何だろう？

WebAssembly.org によると、

> WebAssembly (略して Wasm) は stack ヴァーチャルマシンマシンのためのバイナリ形式の命令セット

とのことである。

この紹介文には「プログラム」という言葉は使われていないし、実際に WebAssembly はプログラム言語では無い。
筆者は WebAssembly とはプログラムのロジックを抽象化するための規格だと考えている。

「プログラムのロジックを抽象化するための規格」とはどういう意味で、何のために行うのだろうか？
本書ではコンピューターの歴史を振り返りながら WebAssembly について語っていく。

## キーワード

本資料のキーワードは "分割" と "抽象化" である。
先にこれらのキーワードについて簡単に説明しておく。

### 分割

大きい仕事というのは、得てして大変な物だ。

- おそらく、部分的に困難な物を含んでいる
- おそらく、不確定要素が多い

こうした要因により担当者は憂鬱になってしまう。
多くの事柄を、一度に、一人で対応するのは難しいのだ。

なので分割してしまおう。

#### タスク分割のメリット

大きい仕事を小さいタスクに分割すると、下記のようなメリットがある

- 複数人で作業を分担できるようになる
    - 各人は、各々の得意分野を担当する事ができる
    - 互いに相談する事ができる
- 作業中は小さく分割された部分に集中する事ができる。これにより、一度に考える必要のある事柄を削減できる。
- タスクを細分化する事で、進捗を見える化できる

#### タスク分割のデメリット

もちろん、分割にはデメリットも存在する。

- タスク分割自体がタスクである
- タスクを分割すると、タスク管理という新しいタスクが発生する

### 抽象化

抽象化とは複雑な仕組みや考えの本質的な部分を取り出して単純化するプロセスである。

コンピューターサイエンスにおいて、抽象化とは「分割」と「外部仕様、もしくは規格の設定」で説明できる事が多い。

なお、「外部仕様」や「規格」が分からない場合は、ここでは「取扱説明書のような物」と認識しておけばよい。

#### 具体例、SD カードの規格

例えば、会社で SD カード 10 種類と SD カードを使うスマートフォン 4 種類を新規に開発するとしよう。

**開発コスト**: (10 + 4) 製品分
**使い方**: (10 x 4) 通り

この方法では少ないリソースで多くの結果を得る事が出来る。

これは SD カードの規格がストレージ部分を抽象化しているからだ。

SD カードはその規格を満たしている。
(SD カードは取扱説明書に記載している通りに動作する)

スマートフォンも、その規格を満たしている。
(スマートフォンは SD カードを取扱説明書通りに使用する)

#### 抽象化のメリット

「少ないリソースで多くの結果を得る」というのは抽象化のメリットの一例だ。
他にも、上記の例から分かるメリットは複数ある。

各開発者は、自分の担当するデバイスだけを理解すれば良い。これは規格によってスマートフォンと SD カードが疎結合になったからだ。

例えこれが会社の最初の SD カード開発事業だとしても、規格通りに動くならば最低限の品質を満たしている事になる。

また、規格は業務の属人化を少なくする事につながりドキュメントの必要性も小さくなる。

#### 抽象化のデメリット

分割と同様、抽象化にもデメリットは存在する。

- 規格を最初に決めるときは困難が伴う
- 後から規格を変更するのは困難な事が多い

### キーワードまとめ

分割と抽象化は必要な労力を減らしてくれる。

これは怠惰な IT エンジニアが好むことだ。
(怠惰とは、美徳である)

怠惰なエンジニアは効率の良い方法を考える事がある。
彼らは効率の良い方法を見つける事に大きな達成感を見出し、そのための労力は惜しまないのだ。

WebAssembly も、そのようにして作られた。

本ドキュメントではコンピューターの歴史を振り返りながら「効率の良い方法」についての具体例をあげ、その流れの中で WebAssembly について解説する。

## 第一世代コンピューター

第一世代コンピューターとは、計算に真空管を使ったコンピューターのことである。
非常に大きく重量が重いので、コンピューター専用の建物が必要であった。

### Atansoff-Berry Computer

Attansoff-Berry コンピューターは電気回路自体がプログラムの役割を果たしていた。
そのため、後からプログラムを変更する事はできない。

エンジニアは、建物、プログラムロジック、電気回路を一度に設計する必要があったのだ。

(ただし、これをコンピューター、プログラムと呼ぶのかどうかは疑問が残るが)

分割したくならないか？

### Colossus

Colossus も、相変わらず電気回路がプログラムの役割をはたしていた。
しかし、配線を変更する事でそのロジックを部分的に変更できたらしい。

つまり、「配線によってロジックの一部を電気回路から分離 (分割) した」と言えるだろう。

### ENIAC

ENIAC は度々アップデートされてきた。
本ドキュメントでは、その最終バージョンのみを取り上げる。

ENIAC はプログラムをメモリに保存していた。
ユーザーはいつでも新しいプログラムを作成する事ができたのだ。

「プログラムの保存方法により、プログラムは電気回路から分離 (分割) した」と言えるだろう。

## 第二世代コンピューター

第二世代コンピューターとは、真空管の代わりに半導体を使ったコンピューターのことだ。
現在のコンピューターのほとんどは第二世代コンピューターにあたる。

半導体素子は真空管に比べて圧倒的に小さく軽い。
そのため、第二世代コンピューターは第一世代に比べて軽量であり、専用建物は不要となった。

これは「半導体が専用の建物の必要性を無くした」と言えるだろう。

### 分離と仕様

ところで、第一世代コンピューターの章で「ENIAC はプログラムロジックと電気回路を分離した」と書いた。

分離できたのならば、今度は仕様を決めたくならないだろうか？

ENIAC 以降の業務フローは、例えば下記のようになった。

1. ハードウェアの仕様を決める
1. 仕様通りに動くコンピューターのハードウェアを作る
1. ハードウェアの仕様に合わせてプログラムを作成する

上記のフローだと、プログラミングに電気回路の知識は不要になる。
また、異なるハードウェアでも仕様が同じならば同じプログラムを使用可能になる。

これは「仕様によってハードウェアを抽象化した」と言えるだろう。

ちなみに、「x86\_64」は CPU の有名な仕様名である。

## Unix と C 言語

仕様を決めたおかげでプログラミングに電気回路の知識は不要になった。
しかし、それでもプログラミングは難しかった。

- プログラマーも専門分野によって細分化されるようになると、ハードウェアの仕様は全ての分野のプログラマーが学ぶには難しすぎた
- 仕様の数だけプログラムを作る必要があった

例として、エディターを作成する事を考えてみよう。

そのエディターは少なくとも下記の事が出来なくてはいけない

- ファイルの保存
- 印刷

さて、プログラムは何種類必要だろうか？
最悪の場合、(プリンターの数) x (保存場所の数) である。

「掛け算の結果」が必要なので抽象化の出番だ

Unix は CPU とメモリー以外のハードウェアを抽象化した。

では CPU とメモリーはどうすれば良いのだろうか？
これは C 言語が抽象化した。

プログラマーは C 言語で Unix 向けのソースコードを書けばよい。
あとは C 言語のコンパイラーが実行可能ファイルを生成してくれる。
(実行可能ファイル: CPU が読んで直接実行できるファイル)

異なる CPU 向けにアプリケーションを提供したい場合はどうすれば良いか？
その CPU の仕様にそったコンパイラーを使えばよい。

(ファイル保存のように)プログラムからハードウェアの機能を使いたい場合はどうすれば良いか？
OS にそのようなリクエストを送信するプログラムを C 言語で書けばよい。
後は OS が何とかしてくれる。

例えば、アプリケーションを作る業務フローは下記のようになるだろう。

1. CPU と、その CPU に対応した C 言語のコンパイラーを作る
1. C 言語で OS を作り、その OS 向けに C 言語のコンパイラーを拡張する
1. アプリケーションのソースコードを書き、コンパイラーを用いて実行可能ファイルを作成する

Unix のおかげでプログラマーは各ハードウェアの仕様をいちいち学ぶ必要が無くなった。
また、CPU の仕様を知らなくとも C 言語でプログラミングできるようになった。

### System Call と User Land

ところで、OS の登場でアプリケーションのプロセスは大きく 2 種類に分かれた。

- OS へのリクエスト
- その他 (CPU とメモリーを直接用いた計算)

「OS へのリクエスト」は「System Call」と呼ばれる。
System Call が使われる代表的な場面は、例えば以下だ。

- Input / Output (なぜなら、input / output にはハードウェアを使うからだ)
- メモリーの確保 / 解放 (これはハードウェアを使うわけではないが、2 個以上のプロセスを同時に走らせるためには誰かが集中管理しなくてはならない)
- ......

「その他 (CPU とメモリーを直接用いた計算)」を呼ぶ適切な名前を筆者は知らないが、これらの処理は「User Land」と呼ばれる権限で行われるので User Land と言うこともある。
(System Call は Kernal Land という権限で行われる。)
User Land の具体例は、例えば以下だ。

- 四則演算
- メモリーアクセス (リード / ライト)
- ......

## Java

Unix と C 言語によりアプリケーション作成は楽になった。
しかし、同時にこれらは別の問題を引き起こした。

例えば、まったく同じハードウェアであっても OS が異なれば同じプログラムが動作しなくなったのだ。

Java は "Java ヴァーチャルマシン (略して JVM)" によって、この問題に対処しようとした。
「Write once, run anywhere」は Java のキャッチフレーズである。

### 「ヴァーチャル」の意味

ケンブリッジ大学の英英辞書によると、「ヴァーチャル」とは下記のような意味である。

1. ある物、品質とほとんど同じである（例文: 10 年に及ぶ無能な政権の統治は、その国の経済にヴァーチャル崩壊をもたらした）
1. コンピューターテクノロジーによって生み出された、物理世界には存在しないが、あたかも存在しているように見える（例文: そのゲームではプレイヤーはヴァーチャル世界の現実味のある生活をシュミレートできる）

なお、IT 業界において「ヴァーチャル」とは「本質的な特徴、機能を全て持っている」という意味である場合が多いと、筆者は個人的に考えている。
(これは「本質的ではない特徴による制限が無い」という意味を含む場合が多い。)

### 「マシン」の意味

IT エンジニアはコンピューターの事を「マシン」と呼ぶことが多い。
ここでは「マシン」の役割とは「アプリケーションを動かす物」という意味だ。

### Java ヴァーチャルマシンとは何か

「ヴァーチャルマシン」とは「アプリケーションを動かす事が出来るので、本物のマシン(コンピューター)とほとんど同じ物」という意味であり、
「Java ヴァーチャルマシン」とは「Java アプリケーションを動かすことができるプログラム」という意味だ。

ただし、ここで「Java アプリケーション」とは「Java ヴァーチャルマシンの規格に沿ったアプリケーション」という意味である。

なお、ヴァーチャルを筆者の個人的な見解で解釈すると「Java ヴァーチャルマシン」とは「Java アプリケーションを動かすというマシンの本質的な機能を持つもの。さらには、電源ケーブルの必要性などマシンの本質的ではない特徴による制限は受けない。」という事になる。

### Java 言語

Java アプリケーション（Java ヴァーチャルマシンの規格にそったアプリケーション）はどうやって作れば良いだろうか？

Java 言語でソースコードを書けばよい。
そうすれば Java コンパイラーによって Java ヴァーチャルマシンが実行可能なファイルを作成してくれる。

### Java まとめ

以上をまとめると下記の様に言う事ができる。

- Java 言語は Java ヴァーチャルマシンを抽象化する
- Java ヴァーチャルマシンは OS を抽象化する

Java アプリケーションの開発フローは、例えば以下のようになる

1. Oracle が、その OS とハードウェアに適した Java ヴァーチャルマシンを作成する
1. プログラマーが　Java でソースコードを書く
1. Java コンパイラーで Java アプリケーションを作る

### 注意

「マシン」の本質的な機能というのは文脈によって異なる。
時には「マシン」が「OS を動かす事が出来る物」を意味する事もあるだろう。

その場合、「ヴァーチャルマシン」という言葉の意味も変わってくる。

## WebAssembly

（Java のように）アプリケーションをヴァーチャルマシンで動かすというアイディアは素晴らしいが、後から考えると下記のように改善の余地があった。

- 「関わる技術」の範囲が大きすぎる
- 「Write once, run anywhere」というのは、実現不可能である

### Java は大きすぎる

「Java に関わる技術」とは、多くの物を含んでいる。

- Java 言語
- Java コンパイラー
- Java アプリケーション
- Java ヴァーチャルマシン
- ......

分割、抽象化したくならないだろうか？

そもそも、ヴァーチャルマシンを使うためには特定の言語でソースコードを書く必要が有るというのは嬉しくない。

ヴァーチャルマシンとプログラム言語は、そもそも全く別の物だ。
ならば、後は規格さえあれば抽象化できる。

### WebAssembly とは

WebAssembly とは、「ヴァーチャルマシンを抽象化するための規格」である。
この規格によって

- 私たちはヴァーチャルマシンやコンパイラーを自由に作ることができる。
- プログラマーは（対応するコンパイラーが存在すれば）自分の好きなプログラム言語で書くことが出来る
- ユーザーは多くのコンパイラー、ヴァーチャルマシンから好きな物を選んで使う事が出来る

WebAssembly に対応したアプリケーションは、どこでも同じように動作するだろう。

**本当にそうだろうか？**

本当だと思うのならば、プリンターの無いコンピューターで印刷してみると良い。

### WebAssembly の制限

「Write once, run anywhere」というのは実現不可能である。
では、どうしたら良いだろうか？

**理想**: WebAssembly はどこでも同様に動作する

**現実**: どんなプログラム（ヴァーチャルマシンを含む）でも、OS やハードウェアの影響を受けてしまう

ここで、「アプリケーションの処理は大きく 2 種類に分かれる」という話を思い出してほしい

2 種類とは

- OS へのリクエスト
- CPU とメモリーを直接使った計算

である。

WebAssembly では、すべてをヴァーチャルマシンで完結する事を諦めた。
WebAssembly は OS 非依存の事しか行わない。
つまり、WebAssembly は OS へのリクエストを行わない。

### WebAssembly アプリケーションの例

ここで平均値を計算するアプリケーションの作成を考えてみよう。
使い方は以下だ。

1. ユーザーはキーボードで数値をいくつか入力する
1. アプリケーションは、その平均値を表示する

ここでは、JavaScript と WebAssembly を両方使ってアプリケーションを作成する事を考えてみよう。

例えば、このプログラムの内部的な処理は下記のようになる

1. OS は JavaScript で書かれたアプリケーションを起動する
1. JavaScript はキーボードから入力された数値を取得する
1. JavaScript は WebAssembly ヴァーチャルマシンを立ち上げる
1. JavaScript はヴァーチャルマシンに数値を渡す
1. ヴァーチャルマシンは平均値を計算する
1. ヴァーチャルマシンは計算結果を JavaScript に渡す
1. JavaScript は計算結果を表示する

もしくは、下記のようになるかもしれない

1. OS は JavaScript で書かれたアプリケーションを起動する
1. JavaScript は WebAssembly ヴァーチャルマシンを起動する
1. JavaScript は入出力に関わる機能をヴァーチャルマシンに渡す
1. ヴァーチャルマシンは渡された機能を使ってキーボードから入力された数値を取得する
1. ヴァーチャルマシンは平均値を計算する
1. ヴァーチャルマシンは渡された機能を使って計算結果を表示する

いずれの場合でも、部分的に WebAssembly 対応のコードでプログラムを書くことが出来る。
WebAssembly に対応した部分に限って言えば、どのコンピューターでも同じように動作するだろう。
しかし、JavaScript のコードも同時に書かなくてはいけない。この部分は動作するコンピューターによって挙動が変わるかもしれない。

### WebAssembly の用途

実際のビジネスにおいて、WebAssembly はどのように使われるだろうか？

例えば、Web Page における JavaScript のコード開発の助けになるかもしれない。

- Web ブラウザーでは、基本的に JavaScript 以外のプログラムは動かない
- 時として、複雑なロジックを JavaScript だけで記述するのは困難である
- WebAssembly は、一般的に JavaScript よりパフォーマンスが良い事が多い

他の言語で WebAssembly 対応のコードを書けば、開発が楽になるかもしれない。

また、WebAssembly 対応の Framework も考えられる。

- たとえば Ruby on Rails の場合、プログラマーは Ruby でコードを書かなければいけない。
- フレームワークを WebAssembly 前提で記載すればコードは好きな言語で書くことが出来るかもしれない。

### イントロダクションの復習

イントロダクションで記載したように、webassembly.org によると

> WebAssembly (略して Wasm) は stack ヴァーチャルマシンのためのバイナリ形式の命令セット

とのことである。
ただし、「命令セット」とは CPU の規格の事で、「stack マシン」とはコンピューターアーキテクチャの一種である。

この文章を、筆者は「WebAssembly とはプログラムのロジックを抽象化するための規格」と解釈した。

## WebAssembly System Interface

ところで、WebAssembly の説明で「諦める」という表現を用いた。
この「諦める」という言葉が嫌いな人も居る。

彼らは WebAssembly に OS とのやり取りを許可するような規格を作った。
これは "WebAssembly System Interface" 略して "WASI" と呼ばれている。

前述の平均値計算アプリケーションの処理フローを思い出してほしい。

1. OS は JavaScript で書かれたアプリケーションを起動する
1. JavaScript は WebAssembly ヴァーチャルマシンを起動する
1. JavaScript は入出力に関わる機能をヴァーチャルマシンに渡す
1. ヴァーチャルマシンは渡された機能を使ってキーボードから入力された数値を取得する
1. ヴァーチャルマシンは平均値を計算する
1. ヴァーチャルマシンは渡された機能を使って計算結果を表示する

この際の「JavaScript から WebAssembly に渡す機能」についての規格を前もって作ってはどうだろうか？

これが WASI の規格である。
WASI では WebAssembly が OS と直接やりとりする機能の一覧を決めている。

WASI は比較的新しい規格であり、今後も短期間に多くの変更が発生するかもしれない。しかし、すでに WASI を使ったエコシステムについて考えだしている人たちも居る。

たとえば、WebAssembly に関する機能を Linux OS に組み込もうと考えている人達がいる。
これにより、ヴァーチャルマシンによるオーバーヘッドが少なくなるだろう。

また、ある人は WASI で OS を作ろうと考えている。
そうすれば、ユーザーはその下にある OS やハードウェアを意識しないで使えるだろう。

### WASI の不確定要素

WASI は理想的な仕組みに思えるかもしれない。

WASI は WASM の良いところを全て受け継いで、さらに「OS にリクエストを送信する」という機能を持っているのだ。

**本当だろうか？**

「WASM はどんな環境でも動作する」

筆者はこの意見に賛同する。
数学的に絶対正しいとは言わないが、ビジネスシーンでは多くの場合問題無いはずだ。

「WASI はどんな環境でも動作する。なぜなら、WASM が元になっているからだ。」

これはちょっと疑わしい。

WASM は、この目的達成のために機能を制限したのだ。WASI はその制限した機能を復活させてしまった。

### 過去の例

例えば HTML の場合、多くのブラウザーが似たような挙動をする。（全く同じとは言わないが）
私たちは規格の恩恵を受けているのだ。

一方、OS の規格である POSIX はどうだろう？
もし POSIX が理想通りにいっていれば、現在のプログラムは全ての OS で同様に動作しただろう。

WASI の規格をうまく決める事は出来るだろうか？
うまくいったとして、WASI は docker のようなコンテナよりも有用になるのだろうか？

WASI が今後どうなるか、現時点では筆者は分からない。
多くの人が WASI の素晴らしさを語っているが、先入観を持たず多様な意見をバランス良くとりいれ、正しく理解したい物である。

## Copying

資料は不変セクションを含む下記の "GNU Free Documentation License Version 1.3 or later" ライセンスの下、https://github.com/wbcchsyn/slide-what-is-wasm.git で公開しています。

Shin Yoshida wrote this document with the goal of contributing to a fair and safe world.
Funai Soken Digital Incorporated agrees with the vision and compensated him for his work.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with one Invariant Sections: “Shin Yoshida wrote this document with the goal of contributing to a fair and safe world. Funai Soken Digital Incorporated agrees with the vision and compensated him for his work.” no Front-Cover Texts, and no Back-Cover Text. A copy of the license is included in the section entitled “GNU Free Documentation License”.