13. 余談: JavaScript に Java は必要ない

元々 JavaScript は Java の弟分のスクリプト言語とみなされ、高度なプログラミングタスクは全て Java で行われることになっていた。しかし JavaScript の経験を積むにつれ、ウェブ開発者たちは自身が本当に必要とするのは JavaScript であることに気が付き始めた。

13.1 エバンジェリスト

JavaScript の利用が広まるにつれ、JavaScript の教育者とエバンジェリスト1が現れた。最も大きな影響力を持っていた人物の一人が Douglas Crockford である。「JavaScript: 世界で最も誤解されたプログラミング言語」という短いオンラインエッセイ [Crockford 2001a] に始まり、彼はソフトウェア開発コミュニティが持つ JavaScript へのイメージを変えるというタスクに取り組んだ。別のエッセイで Crockford [2001e] は次のように説明している:

JavaScript が最初に紹介されたとき、私はこの言語に注意を払う価値は無いと思ってすぐに忘れてしまった。しかしずっと後になって再度 JavaScript を見たとき、私はブラウザに隠されているのが素晴らしいプログラミング言語であることを発見した。私が最初の態度を抱いた原因は初期の Sun と Netscape による JavaScript の位置付けにある。両社は JavaScript を Java と競争する言語に位置付けないために虚偽の説明を何度も行ってきた。そういった虚偽の説明は初心者や「サル」に向けて書かれた質の低い JavaScript 関係の本に氾濫している。

Douglas Crockford [2001d; 2002a; 2003; 2006] は JavaScript が持つ Scheme 風のクロージャや Self 風のオブジェクトを見抜き、その使い方を説明した。しかし彼は JavaScript の欠点や奇妙な点をごまかさなかった。Crockford [2001e; 2002d] は広く使われた最初の JavaScript 用リンター2ユーティリティ JSLINT [Crockford 2001b] を開発し、宣伝した。また Crockford [2001c; 2019b] はミニマイゼーション3という概念を JavaScript 開発者たちに紹介し、JSMIN というユーティリティを開発した。彼は JavaScript の良い部分を使う方法と悪い部分を避ける方法をプログラマに教えるベストセラー [Crockford 2008b] を執筆した。最終的に彼は JavaScript の標準化活動に参加するようになる。

単純さの擁護者だった Crockford は、JavaScript のオブジェクトリテラルと配列リテラルを言語非依存のデータ交換フォーマットとして使えば XML の複雑さを避けられる可能性があることに気が付いた。彼は後に広く採用されるこのフォーマットを「JavaScript Object Notation」略して「JSON」と命名した [Crockford 2002b; Crockford 2019a]。この単純なフォーマットはどんな言語でも簡単にパースでき、特に JavaScript では JSON のデータレコードを eval 関数で JavaScript オブジェクトに変換できるので扱いが簡単だった4

13.2 リッチインターネットアプリケーションと AJAX

初期の対話的ウェブアプリケーションは主にフォームベースだった。ユーザーがデータを HTML フォームに入力し、それをブラウザがウェブサーバーに送信し、ウェブサーバーがそれを処理してデータベースを更新する。ウェブサーバーは更新されたデータを表現する HTML をブラウザに送り返し、ブラウザがそれを表示するというものである。JavaScript は基本的なデータ検証やサーバーが生成した HTML の簡単な動的改変をブラウザで行うために使われていた。このスタイルのウェブアプリケーションは後に「Web 1.0」と呼ばれる5

一部のアプリケーションは対話性が高く、遅延の少ない豪華リッチなユーザーインターフェースを必要としていた。開発者の中からそういった特徴を持つウェブアプリケーションを開発する者が現れるのは不可避だった。1995 年に Netscape が Java と JavaScript をウェブブラウザに搭載することを発表したときの計画は、複雑な対話的ウェブアプリケーションの実装では Java を主に使い、フォームベースのアプリケーションでは主に JavaScript を使うというものだった [Shah 1996]。1990 年代の後半から 2000 年代の初頭にかけて、多くの「リッチインターネットアプリケーション」[Allaire 2002] が Java アプレットとして作られた。

1997 年、Microsoft は自社のエンタープライズメールクライアントのウェブクライアントバージョン Outlook Web Access (OWA) をリリースする [Bilic 2007; Van Eaton 2005]。OWA 1.0 はウェブ 1.0 スタイルのアプリケーションとして実装されたが、次のバージョンは XMLHTTP [Hopmann 2006] という新しいブラウザ API と Dynamic HTML6 (DHTML) を使ったよりリッチなものになった。XMLHTTP があるとウェブページ上の JavaScript コードはページの再読み込みを一切することなくサーバーとのデータのやり取りを非同期に行える。DHTML と XML を組み合わせると、ウェブページはセッションごとにページを一度読み込むだけでデータやサービスに対するリモートアクセスを持つ対話的なアプリケーションとして動作できるようになる。

2000 年代の前半を通して、同じテクニックあるいは似たテクニックを使って様々な組織がウェブアプリケーションを作成した。ただ、このウェブアプリケーションスタイルが広く知られるようになったのは Google が Gmail や Google Maps といったアプリケーションの実装で使ってからだった。Jesse James Garrett [2005] はこのスタイルを指す「AJAX (Asynchronous JavaScript and XML)」という言葉を考案した。AJAX と AJAX を使って作られたソーシャルメディアアプリケーションは Web 2.0 時代を代表する要素となった。

Web 2.0 と AJAX の隆盛はウェブ開発における JavaScript の役割の大きな転換点となった。JavaScript の役割は大部分が静的なページに動的な要素を追加するための言語から、複雑なリッチインターネットアプリケーションをコーディングするための言語へと変わっていった。

同じころ、ブラウザのエコシステムはさらに複雑になり、マーケットシェアが非常に小さいたくさんの代替ブラウザが常に存在するようになった。Netscape (AOL に買収されてから) と Microsoft (マーケット独占を達成してから) は少しずつブラウザ開発から手を引いていったので、新しいブラウザが成長する機会が生まれた。Firefox7 [Mozilla 2004], Opera [Opera 2013], Apple Safari [Melton 2003] そして少ししてから Google Chrome [Kennedy 2008] は徐々にゼロでないマーケットシェアを獲得していった。

新しいブラウザはどれも ES3 という JavaScript 仕様の独自解釈と W3C が部分的に規定するブラウザのプラットフォーム API を実装していた。しかしプラットフォーム API の仕様は不完全あるいは不正確だったので、新しいブラウザのほとんどはプラットフォーム API を様々な形で拡張あるいは改変していた。また新しいブラウザは誕生していたものの、旧バージョンの Internet Explorer や Netscape を使い続けるユーザーも多く存在し、そういったバージョンは最新の言語仕様とプラットフォーム API のサポートを持たずバグも多かった。

ウェブブラウザは他の多くのアプリケーションプラットフォームと一つの重要な側面で異なっている ── ウェブではアプリケーションがソースコード形式で配布され、アプリケーションユーザーによって提供される環境でそれがすぐに実行される。これは開発者がコンパイラとランタイムライブラリの特定のバージョンを選択してビルドと開発を行い、ユーザーにはバイナリ形式だけが届けられる伝統的なシナリオとは異なる。Douglas Crockford8 は様々な場面で、ウェブ開発に特有なこの特徴を「ユーザーが (多くの場合そうと知らずに) 言語処理系を選択する」と表現している。ウェブ開発者は自身のウェブページとウェブアプリケーションがエンドユーザーの選択するブラウザの全てで正しく動作することを保証しなければならない。

ブラウザの差異に対処する一つの方法として、非互換なブラウザのそれぞれに対して専用バージョンのアプリケーションを個別に用意するというものがある。そうしておけば、後はブラウザがウェブページを要求するとき提供される識別情報に基づいてウェブサーバーが異なるブラウザに対して異なるバージョンを送信すれば済む。ただ、普通はアプリケーションのソースコードのほとんどが全バージョンで共通であり、ブラウザの差異に対処するコードは多くない。ここからほぼ同一の中身からなる複数バージョンのアプリケーションを管理するという開発上および実務上の困難が生じる。

複数の異なるバージョンを用意しないで済ませる方法の一つとして、単一のソースファイルを用意しておいて、アプリケーションがブラウザで実行されるときにブラウザ特有の処理を動的に選択するというものがある。ブラウザ特有の処理の選択では browser sniffing (特定のブラウザバージョンを識別する処理) か機能テスト (特定の機能の有無を特定する処理) を行う慣用句的なコードが使われる。

AJAX スタイルのアプリケーションの複雑性、そしてブラウザの相互運用性の問題により、ウェブアプリケーションの構築を簡単にするためのアプリケーションフレームワークとライブラリが生まれていった。初期のフレームワークの例として Prototype [Stephenson et al. 2007], MooTools [Proietti 2006], Dojo [Russell et al. 2005] がある。最もよく採用されたライブラリの一つ [W3Techs 2010] が jQuery [Resig 2006] である。こういった初期のフレームワークとライブラリは通常 AJAX スタイルのアプリケーションの枠組みを提供するのに加えて、そういったアプリケーションがよく行うタスクのコーディングを簡単にするための高レベルな抽象化も提供する。またブラウザが持つ機能の差異を内部で対処、隠蔽することで様々な相互運用性の問題を解決する。

とある種類のライブラリはあまりにも重要だったため、それを表す新しい言葉が生まれた。「polyfill」は Remy Sharp [2010] が考案した言葉で、ブラウザによって提供されるはずにもかかわらず提供されていない API を提供するライブラリのことを言う。上手く設計された polyfill は自身が提供する機能の有無を動的に確認し、ブラウザ組み込みのサポートが不完全もしくは欠けているときに限って機能を提供する。初期の polyfill ライブラリが主に行ったのは、初期のブラウザ競争から引き継いだレガシーな機能差異を隠蔽することでブラウザの相互運用性を高めたり、古いブラウザで新しいブラウザの機能をサポートしたりする処理だった。ある機能が一つの有名のブラウザで利用可能にもかかわらず他のブラウザで利用可能でない状況でも、polyfill があればウェブアプリケーションは同じコードを全てのブラウザで動作させられる。ブラウザの相互運用性が向上するにつれ、polyfill はブラウザあるいは JavaScript の新機能を一足先に提供するための一般的な手段となった。新しい機能の設計プロセスの一環として polyfill ライブラリを作成するのは珍しくない。開発者にとって便利なことに加えて、polyfill を利用すると新しい機能や API について開発者から価値あるフィードバックを得ることもできる。

独立に開発された要素をナイーブに組み合わせることで JavaScript アプリケーションを開発すると、名前の衝突が問題になることが多い。フレームワークとライブラリの多くは名前空間オブジェクトと即時実行関数式9 (immediately invoked function expressions, IIFE) を使ってモジュール化の仕組みを提供する。名前空間オブジェクトとは関数あるいは変数への修飾名付きアクセスを提供するために存在する単なるオブジェクトのことを言う。例えば JavaScript 1.0 の組み込みオブジェクト Math は名前空間オブジェクトである。名前空間オブジェクトの欠点として、含まれる名前は全てパブリックになる。この欠点は 図 22 のように名前空間オブジェクトと IIFE を組み合わせると解決できる:

// モジュールパターンを使ってサービスを定義する
var Services = function () {
  var privateJobCount = 0; // この「モジュール」にプライベートな変数
  return { // 名前空間オブジェクト
    jobCount: function () { return privateJobCount },
    job1: function () { this.privateJobCount++ }
  }
}(); // Services は関数呼び出しの結果に初期化される。
// 名前空間オブジェクトを通じて要素にアクセスする
Services.job1();
console.log(Services.jobCount());  // 1 が表示される
ES3
図 22. JavaScript のモジュールパターンの例。名前を持たない関数式がプライベートな実装を隠蔽する。Services は関数式が呼び出されるタイミングで返り値の名前空間オブジェクトに初期化される。名前空間オブジェクトはプロパティを通して「モジュール」のパブリックなインターフェースを公開する。

このモジュールパターンにはいくつか種類があるものの、IIFE (ときには名前付き関数) の字句的スコープを使ってプライベートな状態を持った関数の集合をカプセル化するという基本的な考え方は変わらない。IIFE が名前空間オブジェクトを返し、パブリックにアクセス可能になる必要があるカプセル化された関数あるいは変数がその名前空間オブジェクトのプロパティを通して公開される。

モジュールパターンを広めた人物として Douglas Crockford の名前が挙げられることが多いものの、このパターンは多くの JavaScript プログラマによって独立に発見されていた可能性が高い。

13.3 ブラウザゲーム理論

ブラウザ戦争 [Borland 2003] の時期、Netscape と Microsoft はウェブサイト用の新しい機能を競争相手より先に導入しようとしのぎを削った。両社は自社特有の機能を開発者に使わせ、「このページを見るなら [XXX] で」という宣伝文句をページに載せようとした。しかしブラウザのユーザーは自分が使っているブラウザでウェブサイトが正しく動かないときイラ立ち、ウェブ開発者はブラウザごとに別バージョンのサイトを用意しなければならないことを嫌った。

Microsoft が技術的手段および非技術的手段の両方を通じてマーケットシェアを Netscape から奪おうとしていたときでさえ、JavaScript の進化には競争に加えて協調が必要になるだろうという認識は存在した。ECMA-262 第 1 版の作業が完了に近づいた 1997 年 7 月の TC39 会合で、Microsoft の Scott Wiltamuth は将来の ECMAScript 開発における協調の誓約 (図 23) を提示している。

異なる道を往く取り組み

Microsoft の ECMAScript 規格における誓約

── 私たちは ECMAScript に影響する新しいアイデアをグループに伝わるよう公開する。内部に隠すことはしない。

── 私たちはグループでコンセンサスに達したアイデアを実装する。

── 私たちはグループが採用するアーキテクチャ的指針に従う。指針を無視したり指針と矛盾したりするものをリリースしない。

── 私たちは ECMA に提出することなしに ECMAScript の言語拡張を出荷しない。

── 私たちは ECMA が承認した ECMAScript 規格を全て実装する。

── 私たちは未承認の ECMAScript 機能をサポートするとき、それは承認されていないとはっきり明示する。

図 23. 1997 年 7 月の TC39 会合 [TC39 1997g] で示された Microsoft の誓約

Brendan Eich は、ブラウザ実装者が自身の製品を改善するためにできることがマーケットの都合によって大きく制限される事実にあるとき気が付いたこと覚えている。例えば次のような事実が存在する:

Eich はこの状況がナッシュ均衡 [Nash 1950] に似ていることに気が付き、ブラウザ実装者が置かれる制約を指して「ブラウザゲーム理論」という言葉を考案した。

一つ目の事実は「ウェブを壊すな!」というスローガンとして表現されることもある。ウェブページは通常サーバーに HTML と JavaScript のソースコードとして保管され、ユーザーがページにアクセスするたびにブラウザによってその都度解釈される。頻繁に使われるにもかかわらず元々の著者が管理していないウェブページは多く存在する。現在でも利用されているものもあれば、歴史的な価値があるものもある。サーバーに保管されるソースコードの解釈を変える破壊的変更を行うと、ページは読めなくなったり機能しなくなったりする。そういった変更が一つのブラウザでしか起きないなら、ユーザーは他のブラウザに乗り換えるだろう。あるいは、そういった変更が全てのブラウザに普及したなら、管理されていないウェブの一部は永久に壊れたままになる。この事実はウェブ規格の作成者も制限する。規格を通して新しい機能や強制的な変更を導入したとしても、少なくない既存のウェブコンテンツが正しく表示できなくなるとブラウザ実装者たちが考えたなら、彼らは規格を無視するだろう。

ウェブの相互運用要件とオープンな規格による基礎が一方的なプラットフォームの革新による競争を制限することを現在のブラウザ開発者は一般に理解している。ブラウザは性能、セキュリティ、信頼性、利便性といった実装の質で競争できるし、実際この競争は行われている。しかしブラウザというアプリケーションプラットフォームの基礎的な技術的機能を前進させるには、全ての主要なブラウザの協調が欠かせないことが多い。

ブラウザゲーム理論は JavaScript の進化における重要なファクターであり、JavaScript が成功した理由を考える上で一つの視点を提供する。またブラウザゲーム理論は JavaScript の歴史の中で起こったイノベーションの成功あるいは失敗の多くを説明する要素でもある。


  1. 訳注: 「エバンジェリスト」は「(福音の) 伝道者」のこと。IT 業界では技術を分かりやすく解説して広める人物のことを「エバンジェリスト」と呼ぶことがある。 ↩︎

  2. 開発時に使われるツールで、ソースコードを検査して疑わしいコーディングプラクティスやエラーが発生しやすい構文を使っていないかどうかを検査する。 ↩︎

  3. JavaScript コメントや不要な空白の削除、そして意味論を保存したソースコードの変形を行うことで、JavaScript プログラムのダウンロードサイズを機械的に削減すること。 ↩︎

  4. JSON の処理に eval を使うことはアプリケーションをコードインジェクション攻撃に晒すセキュリティハザードであると現在では認識されている。現代的な JavaScript エンジンは専用の JSON パーサーを使っており、そういった攻撃の影響を受けない。 ↩︎

  5. Web 1.0 と Web 2.0 という単語を早くに使用した例として DiNucci [1999] による記事がある。 ↩︎

  6. Dynamic HTML (DHTML) とはアクティブなウェブページの HTML 要素を JavaScript を使って動的に改変する技術のこと。 ↩︎

  7. Brendan Eich が主任設計者を務めた Netscape の Mozilla プロジェクトが生んだ副産物。 ↩︎

  8. 個人的な会話, 2019. ↩︎

  9. 即時実行関数式はブロックスコープの代わりとしての役割を果たす。このテクニックは Scheme プログラマに知られていたもので、JavaScript プログラマは 2000 年代半ばから広く使い始めた。IIFE という単語は Ben Alman [2010] によって考案された。 ↩︎

広告