読者です 読者をやめる 読者になる 読者になる

Isomorphic JavaScript

JavaScript Node.js

2013年11月の記事ですが、JavaScriptを学習し始めて数ヶ月の自分には(英語のイディオム的にも)得るものが多かったので訳しておきます。

Isomorphic JavaScript: The Future of Web Apps - Airbnb Engineering

Author

Spike Brehm @spikebrehm

JavaScript Grows Up

ウェブの黎明期から、ブラウザは、インターネット上のどこかにあるサーバーにHTMLページを生成し、それを送り返すことでブラウジングを行っていました。ブラウザが強力でなく、HTMLページがほとんど静的でそれだけで機能するドキュメントを表現していたため、問題はありませんでした。動的にウェブページを動かすために作られたJavaScriptは画像のスライドショーやデータ収集ウィジェット以上のものを可能にすることはなかったのです。

パーソナルコンピューティングの発達から数年が経ち、クリエイティブテクノロジーによりウェブはその限界まで達し、ウェブブラウザはそれについていくために発展しました。今ではウェブは十分な機能を持つプラットフォームへと成長し、速いJavaScriptのランタイムとHTML5スタンダードによって、開発者は、以前はネイティブ プラットフォームでのみ可能であったような多彩なアプリを開発することができるようになりました。

The Single-Page App

開発者が、こういった新しい機能を活用した、ブラウザで完結したJavaScriptアプリケーションを作るようになるまで、長くはありませんでした。Gmailのようなシングルページアプリケーションでは、ユーザーの操作にすぐさま反応し、新しいページをレンダリングするためだけに、サーバーとの往復をする必要がなくなりました。

Backbone.js, Ember.js, Angular.jsのようなライブラリはよくクライアントサイドMVC (Model-View-Controller)や、MVVM (Model-View-ViewModel)ライブラリと言われます。典型的なクライアントサイドMVCアーキテクチャは次のようになります。

アプリケーションロジックの大部分(views, templates, controllers, model, internationalizationなど)はクライアントに配置され、データ取得のためにAPIを用います。サーバーはRubyPython, Javaと言ったあらゆる言語で書かれ、HTMLの最初の骨格を作り上げます。いったんJavaScriptファイルがダウンロードされると、それが評価され、クライアントサイドアプリが初期化され、APIからデータを取得してHTMLページの残りの部分をレンダリングします。

これはユーザーにとっては素晴らしいものでした。というのも、アプリはいったん読み込まれると、ページをリフレッシュすることなく、ページ間の移動閲覧が可能になったからです。また、正しく読み込まれると、オフラインでも作動しました。

また、これは開発者にとっても素晴らしいものでした。理想化されたシングルページアプリケーションでは、クライアントとサーバーを分けて考えることができ、開発ワークフローが促進され、違う言語で記述されるそれら2つのロジックを共有する必要がほとんどなくなったのです。

Trouble in Paradise

しかしながら、実践的にはこの方法には幾つかの不備がありました。

SEO

クライアントサイドのみのアプリケーションはクローラーに対しHTMLを提供できていないため、デフォルトではSEO (Search Engine Optimazation)が弱いです。ウェブクローラーはサーバーに対してリクエストを送り、その結果を解釈することで機能します。しかし、サーバーが空のページを返したなら、SEOは機能しません。ワークアラウンド(解決法)はありますが、色々と面倒なことがあります。

(訳者メモ: workaround: 一時的な解決策  jump through hoops: (サーカスの動物たちの輪くぐり)苦労する、試練を受ける。)

Performance

同じ理由で、サーバーがHTMLのフルページをレンダリングせず、クライアントサイドのJavaScriptレンダリングするため、ユーザーはブランクページあるいはページのコンテンツが表示される前にスピナーを数秒見ることになります。

Maintainability

たいていは異なる言語で記述されるクライアントとサーバーの間のアプリケーションロジックとビューロジックが複雑になることが避けられないことがあります。よくあるのが、日付や通貨のフォーマット、認証フォームとルーティングロジック。特に複雑なアプリなら、メンテナンスが悪夢と化します。

この方法に夢中になっていると考える開発者もいます。というのも、シングルページアプリケーションの構築に時間と努力を投資して初めて、欠点がどういうものかはっきりするからです。

(訳者メモ: be bitten by ~: ~に夢中である drawbacks: 欠点)

A Hybrid Approach

結局のところ、新しいものと古いもののハイブリッドが欲しくなるわけです。パフォーマンスとSEOのためにサーバーから完璧なHTMLが渡されればいいのですが、クライアントサイドアプリケーションのロジックにスピードと柔軟性も欲しいのです。

そのためにもAirbnbはクライアントサイドとサーバーサイド両方で動くJavaScriptアプリケーションである、"Isomorphic JavaScript"アプリを試みてきました。

(訳者メモ: at the end of the day: 要するに、最後には  to this end: このために、この目的を達成するために)

"Isomorphic"なアプリはこのようになります。"Client-server MVC"とここでは名付けておきましょう。

この中では、アプリケーションとビューロジックはサーバーとクライアント両方において実行されます。これはすべての可能性を切り開きます。つまり、パフォーマンスの最適化、保守性の向上、デフォルトでのSEO、よりステートフルなウェブアプリへの可能性です。

速くて安定したサーバーサイドJavaScriptランタイムのNode.jsによって、これが現実のものとなりました。サーバーサイドとクライアントサイド両方で動くアプリケーションロジック、"Isomorphic JavaScript"の定義を、適切な抽象化を行うことで、記述することができます。

Isomorphic JavaScript in the Wild

このアイデアは新しいものではありません。2011年にはNodejitsuが"Isomorphic JavaScript"アーキテクチャの素晴らしいディスクリプションを書きました。しかし、採用するには遅くなってしまいました。すでに幾つかの"Isomorphic"フレームワークが現れています。

(訳者メモ: spring up: ひょっこり現れる、存在に至る)

Mojitoは初めてのオープンソースである"Isomorphic"なフレームワークとして評判を得ました。これは進歩をとげたフルスタックのNode.jsベースのフレームワークですが、YUIに依存があり、Yahoo!-specifi quirksは2012年の春にオープンソース化されるまでそれほど人気はありませんでした。

Meteorはおそらく今日では最もよく知られた"Isomorphic"プロジェクトでしょう。Meteorはリアルタイムアプリをサポートするためにゼロからビルドされました。Meteorのチームはパッケージマネジャーとデプロイメントツール周りのエコシステム全体を作り上げました。Mojitoのように、これは大規模なNode.jsフレームワークでしたが、JavaScriptコミュニティの興味を惹き、待望の1.0リリースはもう直ぐそこです。Meteorは目をつけておくべきプロジェクトです。オールスターのチームを募り、Andreessen Horowitzから$11.2 Mを得ました。

Facebookの共同設立者Dustin Moskovitzによって設立されたタスクマネージャアプリAsanaは"Isomorphic"に関する興味深い話があります。Asanaでは、世界でもっとも若いビリオネアであるMoskovitzのステータスを考えると、"Isomorphic"なJavaScript周辺で最も進歩した例である、クローズドソースのLunaフレームワークのR&D開発に年数を費やしました。もともとは、Node.jsが誕生する前のv8cgiの上にビルドされたLunaによって、ユーザーのシングルセッションの度にサーバー上で、アプリの完全なコピーを実行することが可能になりました。ユーザーごとにサーバープロセスが異なり、クライアントで実行されるJavaScriptコードが同じであることで、強固なオフラインサポートと高頻度のリアルタイムアップデートといった先進的な最適化が可能になりました。

今年の初め、"Isomorphic"ライブラリをローンチしました。Rendrはサーバーサイド上で完全なレンダリングすることができるBackBone.js + Handlebars.jsシングルページアプリケーションのビルドを可能にします。RendrはAirbnbモバイルウェブアプリをリビルドした経験から生まれたもので、特にモバイルコネクションの反応速度に重要な、ページ読み込みの時間を劇的に改善しました。Rendrはフレームワークというよりライブラリであろうとしています。そのため、変更や拡張は簡単です。

(訳者メモ: much-anticipated: 待望の  around corner: すぐ間近になって、角を曲がった先に  keep tabs on: 監視する、記録する)

Abstraction, Abstraction, Abstraction

クライアントとサーバーの環境はかなり違うので、アプリケーションロジックと裏で実行されるものとを分けて抽象化しなければなりません。そのため、アプリケーションのデベロッパーに対し、シングルAPIを提供します。

(訳者メモ: dissimilar: 異なる、相違する decouple: 切り離す underlying: 裏にある、根本の)

Routing

URIパターンをマッピングする一連のルートによりハンドラをルーティングします。ルートハンドラはHTTPヘッダ、クッキー、URI情報にアクセスする必要があり、直接 window.location (browser)あるいは req, res (Node.js)にアクセスすることなくリダイレクトを設定します。

Fetching and persisting data

フェッチングの仕組みからすぐに特定のページやコンポーネントを即座にレンダリングする必要のあるリソースを説明します。リソースの記述語はJSONのエンドポイントを示すシンプルなURIでなければなりません。あるいは、大規模なアプリケーションなら、モデルやコレクションの中でリソースを要約し、ある程度まではURIへと変換されたモデルクラスとプライマリキーを指定するのに便利でしょう。

View rendering

DOMを直接操作するか、文字列ベースのHTMLテンプレートを使うか、あるいはDOM概念のUIコンポーネントライブラリに依存関係を持つかどうかに関わらず、同形にマークアップを生成する必要があります。アプリケーションの必要に応じて、サーバー、クライアントのあらゆるビューをレンダリングすることが可能です。

Building and packaging

GruntやBrowserifyのようなツールはアプリの構築と実行を行うためのワークフローの一部分として不可欠です。アプリのビルドには幾つかの段階がありえます。テンプレートのコンパイル、クライアントサイドの依存関係の解消、トランスフォーム、圧縮等です。シンプルなケースでは、すべてのアプリケーションコード、ビュー、テンプレートをひとつのバンドルにまとめ上げますが、大規模なアプリだと、読み込むのに数百KBにもなります。より進んだ方法としては、動的なバンドルを作り、遅延読み込みアセットを導入する方法がありますが、これはすぐに複雑化します。Esprimaのような静的な解析ツールを使うことで、革新的な最適化とメタプログラミングによって、ボイラープレートのコードを減らすことができます。

Composing Together Small Modules

市場初の"Isomorphic"フレームワークであることは、これらの問題を一手に引き受けることを意味します。しかし、これは既存のアプリに適応し融合させることが困難であるような、大きく非効率的なフレームワークに至らせます。多くの開発者がこの問題に取り組む中で、"Isomorphic"なアプリをビルドするため互いに統合することができる、小さな、再利用可能なモジュールが急増するでしょう。

ほとんどのJavaScriptモジュールはすでに、少しの変更あるいは変更なしに"Isomorphic"として使われます。例えば、Underscore, BackBone.js, Handlebars.js, Moment, jQueryといった人気のライブラリでさえ、サーバー上で使用することができます。

この点について説明するために、GitHubで見ることができる簡単なアプリisomorphic-tutorialを作りました。"Isomorphic"である幾つかのモジュールを組み合わせて使うことで、数百行のコードで簡単な"Isomorphic"アプリを実現しています。サーバーにDirector、ブラウザベースのルーティング、HTTPリクエストにSuperagent、テンプレートにHandlebars.jsを使い、Express.jsのトップにビルドしています。もちろん、アプリが複雑化するにつれて、より多くのアブストラクションレイヤーを導入する必要があります。しかし、もっと多くの開発者がこれを経験することで、新しいライブラリとスタンダードが出現することを望みます。

The View From Here

Node.jsの実行が快適になるにつれて、クライアントとサーバーのコードを共有するウェブアプリが多くなることは避けられないことです。"Isomorphic JavaScript"はスペクトルであることに注意しましょう。どんなJavaScriptコードがどのようにビルドされたアプリケーションの環境に依存します。

Nicholas C. Zakasが書いた、UIレイヤーをクライアントからサーバーにプルダウンし、パフォーマンスと保守性の最適化を可能にするアプリの見解についてのディスクリプションがあります。アプリはバックエンドをNode.jsと取り替え、"Isomorphic JavaScript"を使う必要はありません。実用的なAPIとRESTfulなリソースを代わりに作ることで、従来のバックエンドはNode.jsレイヤーと共存することができます。

Airbnbでは、クライアントサイドのビルドプロセスを再編成し始めており、GruntとBrowserifyのようなNode.jsベースのツールを使用しています。メインのRailsアプリがNode.jsアプリに取って代わることはないでしょうが、これらのツールを採用することで、環境間のJavaScriptとテンプレートの一部分を共有することが容易になります。

これはここで始めて聞くかもしれませんが、数年以内に、サーバー上でJavaScriptを動かさないウェブアプリが珍しくなるでしょう。