この記事はGoogle I/O 2014で開かれた Upgrading the engine mid-flight: How Google improves its web apps without downtime というセッションの動画の内容を自分なりに解釈して要約して日本語でまとめたものです。正しい和訳ではありません。下記URLの動画を見ながら読んでもらえればよいかと思います。
https://www.youtube.com/watch?v=rKnR8hplUdY
イントロダクション
去年のI/Oで私は、クールで新しい技術を簡単に、パワフルに使うことが出来るようになったことに大いに興奮した。しかし毎朝会社に向かいコンピュータの前に座ると、読むのに15~20分かかり、どんな内容だったか思い出せないコードに失望した。
クールな技術を利用して開発を楽しくするために動き出したが、膨大なレガシーコードとそれを使うすべてのツール、どこから手を付ければよいのかわからなかった。私は政府の請負でもないし銀行で働いているわけでもなく、古い学校のシステムを作っているわけでもない。 私はGoogleで働いている。 新しい技術を生み出しているGoogleですらこのような問題があるのだ。
Polymerをはじめ我々の全てのアプリケーションは魔法のように生まれたのではなく、我々が発明したものだ。毎日のようにアップグレードし、新しい技術を取り入れようとしている。これは我々だけでなく多くのオーディエンスも関係する話だろう。そこで我々は今日、我々のアプリケーションをアップグレードしたいくつかの挑戦と、それを実現するための戦略を教えようと思う。
4つの戦略
我々の戦略について、4つの大きな領域に分けて話そう。
1つ目はどんなアプリケーションにも通じる話だ。巨大なアプリケーションをどのようにして細分化したかについて話そうと思う。
2つ目はテストについて。巨大なアプリケーションをリリースした日はちゃんと動くかもしれない。だが次の日、3日後にそれを確かめる方法は?我々がテストをどのように行い、何が重要だとわかったのかを話そう。
3つ目はどのようにエンジニアの生産性を良くしたかについて。我々は機能的で、ビルドも速い開発環境を仕事に使えるようにした。どうやって使えるようにしたのか、そして我々が選んだツールを紹介しよう。
そして最後に、Dartがこれまでの3つをどのように結びつけたかについて話そう。
アプリケーションの細分化
巨大なアプリケーションを新しい言語に切り替えるにはどうすればいいか。
我々が持っているのは小さなブログページではなく百万行のコードと数百人のエンジニアで出来ていて毎週のようにアップデートされる巨大なフロントエンドだ。一つのJavaScriptバイナリの中に多くの小さなモジュールが存在する巨大なフロントエンドでは、一つを取り出して独立に扱うのは困難だ。
我々は一つのページのアプリケーションをいくつかのサブアプリケーションに分け、別々のバイナリにした。一つ一つのアプリケーションを他への影響を考えずに個別にリプレースできるようになり、それぞれの機能について開発チームを分けることも出来た。
これが一つ目のアイデア、一つのシンプルなインタフェースだ。今ではグローバルというのは一般には良くないとされるが、このケースでは我々に多くをもたらした。
複数のプログラミング言語への対応
違う言語で書かれたアプリケーション間で同じコードを共有したいが、重複させたり、書きなおすのはやりたくないことだ。そのために我々は常にソースの一元化という戦略を取った。APIを別々の言語で手書きするのではなく、一元化されたソースを使い、他の言語のAPIを生成することにした。
GoogleではProtobuffer(※Protocol Buffer)を至るところで好んで使う。Protobufferを使うとJavaのコードもDartのコードも簡単に生成できるし、他にもいくつかの言語に対応している。Protobufferの他にもJSONやThrift、Google Cloud Endpointを使うことで多くの言語に対応することは出来るだろう。
テストの作り方
我々の周りでは全てがどんどん変わっていく。我々はAngularを使っているがAngularチームは毎日毎週システムを改良している。Polymerも同様だ。全世界のライブラリは変わっていく。これらを全て正常に動くかどうか確かめるか、それを解決する唯一の方法はテストカバレッジだ。
Googleではテストのサイズを3つのカテゴリーに分けている。
- 小規模テスト
- 中規模テスト
- 大規模テスト
小規模テストは100ms以下のとても速いテストで、ほとんどはユニットテストだ。中規模テストは約1秒程度のテストだ。UIテストやインテグレーションテストのようにまだ速いが少し複雑なものがここに含まれる。大規模テストは15分程度かかるようなテストだ。フルスタックテストや、パフォーマンステスト、ブラウザからの入力や選択を自動化したテストなどがある。
大規模テストのカバレッジは10%程度でよい。頻繁に行いたいものではないし、正常に動くかどうかを確かめるだけのスモークテストやストレステストであることが多いからだ。中規模テストは50%、小規模テストは70%ほどのカバレッジが欲しい。
ユニットテスト
ユニットテストは小さければ小さいほうが良い。一つのアクションに対する一つの反応をテストするのが好ましく、決してひとつのユニットテストで全ての検査をしようとしてはいけない。別の開発者がやってきたとき、それが一つのテストが失敗したのか4分の3のテストが失敗したのかわからないからだ
非同期テスト
Dartを使うと非同期テストは少し簡単になるが、Angularを使うと非常に簡単に書くことが出来る。Angularはタイムトラベルによって非同期テストを同期テストにすることが出来る。
UIテスト
UIテストは大変で我々は書くのが好きではないが、これもAngularが助けてくれる。TestBedを使うことで簡単にAngularのコンポーネントやディレクティブをセットアップし、DOMの操作やイベントの送信などではなく、Angularのオブジェクトでテストすることが出来る。
インテグレーションテスト
どのようにして隣のチームがインタフェースを変えていないこと、あるいは破壊的な変更をしたことを確かめればよいか。これを解決するのがインテグレーションテストである。インテグレーションテストは利用しているライブラリの全てに行う必要はなく、実際に影響のある部分だけを確かめれば良い。
継続的インテグレーション
AngularDartプロジェクトは誰もがページをチェックして正常に動作するかを確かめられるように、Travisを使っている。
Angularについて
大量のDOM、divのスープを抱えてフロントエンドを作るのは大変である。この問題を解決する戦略は、HTMLと戦わないことだ。HTMLを拡張し、DOMをパワフルにする、そのために我々はAngularDartをピックアップした。
AngularDartはPolymerと同じ概念を持っていて、モデルとHTMLをバインドするためのシンプルなビヘイビアを与えてくれる。AngularDartが強力なのはすでに書かれているHTMLにビヘイビアを書き足すだけで使うことが出来るからだ。非常にシンプルなビヘイビアを歯車のように組み合わせて、短時間で巨大で機能的なUIを作り上げることができる。
歯車はとても単純だが、時計は簡単である。アプリケーションを作るときに重要なのは単純であることと簡単であることの違いを理解することだ。歯車は自分で作れるくらいシンプルだが、簡単に組み込むことができる。一方、時計は包括されていて使いやすく便利だが、時計を別の時計に組み込むことはできないし、解体して全ての歯車を取り出さないと別の時計は作れない。それは簡単かもしれないが、単純ではない。これらは別々の目的があって、どちらにもいいところがある。(※おそらく歯車…Angular、時計…Polymer)
今日は多くのPolymerコンポーネントを見てもらったが、Angularは同じ基盤の上で構築されている。Shadow DOM、Web Components仕様を使い、同じ概念の技術を使っている両者の違いはわずかだ。(※AngularComponentsへの布石?詳しい説明はなし)
Dartについて
Dartは我々に必要な全ての要素を備えている。まずDartは普通に書かれたJSと同じくらいの速さで動くのが最大のポイントだ。また、Dartが我々に与えてくれた最も良いことは型である。型があることで我々はリファクタリングが可能になった。さらに型はコンパイル後のJavaScriptを最適化し、より速くしてくれる。
次にDartは我々にパッケージマネージャを与えてくれた。Dartのパッケージマネージャは全ての依存関係を管理してくれる。もうどのパッケージマネージャを使うかで争う必要はないのだ。
おかしい点や付け足したほうが良い点などあればコメントで教えてください。