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

ブログを書くまでがHTML5 Conference 2013

tech

2013/11/30にHTML5 Conference 2013が行われました。 運営の方々、スピーカーの方々お疲れ様でした。当日は風邪を引いてしまい、参加できなかったのですが、YouTubeでリアルタイムに見みることができて非常にありがたかったです。

で、ブログを書くまでがHTML5 Conference 2013ということで、拝見した各セッションについて感想を書いてみました。 (僕は各セッションを聞きながらTwitterクライアントやLINEのようなアプリをモバイルWebアプリで作るのにどんな役に立つのかなという視点で見ていたので、感想もモバイルWebアプリを中心としたものとなっています)

  • モバイル時代のフロントエンド開発レシピ
  • 実践的なモバイルHTML5テクニック
  • 満足させるハイブリッドアプリを作るための実践テクニック
  • 地下鉄 x サクサク x これからのWebゲームアプリが備えるべき8つの機能
  • Webフロントエンドのレンダリングパフォーマンスと最適化Tips
  • Web をまともにしたいので Shadow DOM と Web Components をつくってます
  • Knockout による大規模 JavaScript 開発 (スペシャルセッションのLT)

モバイル時代のフロントエンド開発レシピ

@さんがモバイルWebフロントエンドを開発する上でのトピックをCode、Performance、Automationに分類してお話されていました。

その中で気になったのがCSS周りの話。キーワード的にはOOCSS、SMACSS、BEMあたりがでてきました。僕はこれらを初めて聞きました。簡単に言うと「CSSを構造化して再利用可能なモジュール、パーツに分けて記述し、パターン化しよう」というものと理解しました。(SASS、LESSについて出てこなかったのはそんなもの知ってて当たり前みたいな感じなのかな?)

確かにCSSって何回も同じような記述繰り返したり、コードがすぐに肥大化したりして大変だとは思うのですが、装飾についてオブジェクト指向って本当に必要なんだろうか?というのが率直な感想です。

僕はJSを中心に仕事を行っているのですが、SASSを少し書いたりもします。SASSは生CSSに比べて本当に激的に生産性/保守性というのは上がっている気がします。OOCSSというのはその先に見据えた話なのかなと。ただそれでもCSSにはスコープがない(あるHTMLタグのスタイルを指定するのにCSS中のどこからでも指定できてしまう)ので、ブラウザ上でデバッグする時は結局CSSすべてを理解しないといけないはめになってすごく辛い思いをしています。

いっその事、タグのstyle属性にすべて書き込んでしまってもいいんじゃないかと思ってさえいます(ブラウザもカスケードの処理をしなくて楽ちん!)。そういうとすごく反感を買いそうですが、HTML/CSSをテキストとして開発/保守しているからstyle属性に書いてしまうと大変になるのであって、GUIを使ってもっとビジュアルに開発/保守できればHTMLとCSSを分離しなくてもいいんじゃないかと。そしてそのレイアウトは再利用できる仕組みがなければならないと思っています。例えばTwitterのタイムラインに流れてくるツイート。あの構造/デザインはtwitter上でたくさん使われるので、当然1つ作ってそれを再利用したいはずです。で、再利用元を変更すれば当然すべての画面でその変更が反映される。

それとレイアウトだけじゃなくて画面のスタック管理、ライフサイクル、画面間でのデータ送受信の仕組みなどアプリを作る上での包括的な仕組みがあってもいいんじゃないかと思っています。ようはAndroidやiOSのSDKみたいなフルスタックフレームワークと開発環境です。そういうものがあればWebフロントエンドの開発も違ったやり方ができるんじゃないかと。現在そういったものがWebフロントエンド界隈に無いのは、サーバサイドで動的にHTMLを作成してブラウザに出力し、URL遷移を必要としていたものが今までは多かったからかなと推測しています。でも今はサーバサイドはAPIだけを提供してJSで動的に画面を構築し、単一URLのみのSPAでアプリを作るという流れになってきているので状況が変わってきています。

と、まあこんな感じで僕はCSSだけをオブジェクト指向にして開発していくのに懐疑的です。だってデザイン(装飾)だけを扱うんじゃなくて、構造(HTML)・装飾(CSS)・振る舞い(JS)を1つにまとめて再利用できる形(タブやボタンやリストなど)にすべきじゃないかと。

ちなみにSencha Architect というプロダクトがかなり思ってるものに近いのかなという印象です。他にもcodiqaApplication Craft とったものもあります。思想的にはHTMLを拡張してWebアプリを作りやすくするという点でAngularJS も気になっています。

実践的なモバイルHTML5テクニック

@さんがWebとネイティブの比較、Webの良さ、Canvasにおけるパフォーマンス改善やAndroidのバグについてのお話をされていました。

Webとネイティブを比べて紀平さん一押しの利点は「インストール不要」ということをあげていました。URLを友達に伝えれば一緒にゲームを始められたり、ゲーム中での自分の成果を共有できたりという例をあげていました。確かにネイティブに比べてその点は非常に魅力的だと思います。僕個人もモバイルWebが好きで、なぜ好きなのかをちょっと整理してみるとこんなかんじです。

  • まだまだ発展途上なので自分でも参入できる分野
  • プラットフォームにロックインされずに更新できる
  • インストール不要
  • 既存のWebサービスと相性が良い(開発スタイル、開発者、コードの再利用など)
  • マルチプラットフォーム

反対に欠点は「実行速度が遅い」「互換性」「ハードウェアのAPIが使えない」などをあげていました。この中で「実行速度が遅い」部分にフォーカスして話が進んでいきました。僕も実行速度(パフォーマンス)について今非常に興味を持っているところです。Webの欠点の中でも僕達フロントエンド開発者が直接問題を解決できる部分がパフォーマンスの部分についてだからというのが大きいです。

その後はCanvas上でのパフォーマンスチューニングについて濃い話が色々でてきて非常に面白く聞かせていただきました。基本的にAndroidをベースに話されていたような印象です。iOSについてはあまり話題に上らなかったのはパフォーマンスがAndroidよりも数段出るからなのかなと思います。僕もAndroid/iOS対応のWebゲームを作った時にやっぱりiOSはAndroidに比べて数段スムーズに動いてくれました。何となくの印象ですが、AndroidがiOSにWebの性能で追いつくのにだいたい2年前後かなと。(つまり後2年で今のiPhone5なみの性能がAndroidでも出せる!?)

  • iPhone4S 2011/11 発売
  • GalaxyS4 2013/04 発売
  • Nexus5 2013/11 発売

パフォーマンスチューニングの話はAndroidの苦しいバグについての話でした。笑いながらお話されていましたが、そのバグ報告を受けた時は笑い事じゃなかっただろうなと思います(笑)そしてそのよくわからないバグたちをバッサリ倒していく秘訣を教えて欲しいところです。やっぱり経験とセンスなんですかね。

Android2.2時代にCanvasを触っていたんですが、文字の折り返しが動かなかったのとAndroid/iOSでShadowの向きが違うバグとか合った気がします。今はどうなったんだろう。それとiOS7のUIWebViewは結構ひどくて、overflow:scrollな要素をグリグリしてるとSEGVで落ちたり、selectタグをグリグリしてるとSEGVで落ちたりとAndroidを笑っていられない状況です。ちなみにiPodTouch + iOS7でよく再現します。解決方法はoverflow:scrollの場合はJSでスクロールを実装、selectタグをネイティブUIを使わずに自前のリストを表示というので回避しました。

Canvasのゲームとしてダンジョンポッパーが紹介されていました。このゲーム、本当に非常によく出来ていてすごいなーと。で早速Android Chromeで分析しようとしてコンソールを立ち上げると、何故かゲームが遊べない。コンソール立ちあげるとゲーム遊べないトラップでも仕込んでいるんだろうか。それとも僕も環境が何か悪かったのかな。もしトラップ仕込んでるなら方法をすごく知りたい!

満足させるハイブリッドアプリを作るための実践テクニック

@さんがWebViewを使ったハイブリッドアプリ、PhoneGap、実践テクニックなどを紹介されていました。

Packaged Web Appsという仕様があるのを知らなかったので、仕様化されてるんだーと驚きました。話の中心はiOSでいかにしてWebのUIをネイティブUIに近づけるかというところとパフォーマンス周りのチップスでした。基本的にiOSを使ってお話されていたので、AndroidでのPhoneGapのパフォーマンスやバグはどうなんだろうなというのが気になるところでした。僕はPhoneGapを使ったことがないので想像なんですが、Androidでのパフォーマンス改善やバグって結構トリッキーな方法で回避したりするので、PhoneGap本体のコードもいじってプロダクトに含めることができないと辛いのではという印象です。

Android4.4でWebViewがChromeベースになったのでWebViewのリモートデバッグもできるようになったよという話をされていました。方法は簡単で数行のコードをJavaで書いてWebViewをリモートデバッグでいるようにして、Chromeにつなげるだけです。 https://developers.google.com/chrome-developer-tools/docs/remote-debugging?hl=ja#debugging-webviews

iOSはiOS6からリモートデバッグできるようになっていて、Mobile Safariの設定でWebインスペクタを有効にしてMacにUSBで接続すればMac Safariからデバッグすることができます。UIWebViewも同様にできますが、アプリがデバッグビルドされていないとできなかったと思います。

あとiOSでJSからUIWebView経由でネイティブAPIを実行する部分をどうやってるのか気になります。通常JSからlocation.href = ‘myapp://command’みたいな形でUIWebViewにコマンドを通知してUIWebView側でshouldStartLoadWithRequestでキャッチします。しかしlocation.href = ‘myapp://command1’; location.href = ‘myapp://command2’; とするとcommand2しかUIWebViewに通知できません。なのでキューイングして一気にコマンドを送る仕組みが必要になってきます。例のようにコマンドを送る部分がコード的に近くに書いてあればいいのですが、プログラム中のいたるところで呼ばれていたりすると結構厄介です。その場合はsetTimeoutを使って現在の実行スレッドを抜けてからキューに溜まったコマンドを一気にUIWebViewに通知するといった泥臭い仕組みが必要になってきます。この辺をもっとスマートに解決しているならPhoneGapに詳しい人、教えてください。

地下鉄 x サクサク x これからのWebゲームアプリが備えるべき8つの機能

(uupaaさんは実在した!)

@さんがWebアプリをサクサクで動かすためのパフォーマンス改善のお話をされていました。紀平さんがCanvas周りのJSについてお話されていたのに対して、uupaaさんはその周辺部分についてよりパフォーマンスを上げるにはみたいな観点だったと思います。

WebWorkers(スライド中ではWebWorkerという表記だったけど、W3C的にはWebWorkers?)を使って、計算処理はUIスレッドじゃなくて専用スレッドで行おうという話がありました。僕はまだWebWorkersをプロダクトで使ったことは無くちょっと実験してみた程度です。その時はHTMLの文字列を動的に生成してinnerHTMLに突っ込むという処理のうち文字列を生成するという部分をWebWorkersで実行してみました。iOSのUIWebViewで使ってみたんですが、本当にすごい爆速でした。UIWebViewはJITが効かないことが有名ですが、巨大なHTML文字列を生成させようとするとUIをかなりブロックしてしまいます。でもWebWorkersを使えばUIブロックをせずに処理を行えて感激しました。ちなみにAndroidはJITが効くようなので、非常に重いJSの処理であればiOSよりも良いパフォーマンスをだします。この実験の時はWebWorkersを使わなければAndroidの方がパフォーマンスは上でした。

また計算処理だけじゃなくて通信(XHR)のプロキシとして使えばオフライン時の挙動をWebWorkers内に閉じ込めてオンラインに復帰した時にためておいた通信を再開するというような使い方もを提案されていました。実用的で非常に良さそうだなと思いました。

ただし、WebWorkersって起動コストがそこそこあります。PCでは気にしなくても良いのですがモバイルだと手元のXperia SX(Android4.1, Chrome31)だとだいたい50ms~80ms程度かかってしまいます。これは無視できない時間なのでほいほいとWebWorkersを立ち上げるわけには行きません。

そこでスライド冒頭にもあったSPA(Single Page Application)です。SPAにしておくことで必要なWebWorkersを一度立ち上げるだけですみます。後はそのWebWorkersを使い回せば良いだけです。しかもSPAにすれば800ms → 200msとページ遷移の時間を節約できるらしいし、いいこと尽くし!(600msの時間節約は全ページ共通のJS/CSS読み込み時間/Eval時間を起動時に一度だけ支払えば良いという理由からだと思います)

読み込みの時間といえばlocalStorageとJSファイルも気をつける必要があります。localStorageもモバイルだと数文字readするだけでも30msかかったりします。JSファイルも10ファイルを個別にscriptタグで読み込むのとcatで1ファイルにまとめたものだと100ms前後の時間差があったりします(もちろんキャッシュに乗っている前提で通信しない状況で比較)

アセットマニフェストという考え方も紹介されていて、これと同じようなことを半年くらい前に検証していたのでびっくりしました。manifest.json的なものに必要なリソースパス、ハッシュ値、タイムスタンプなんかをまとめて、クライアント側は自身のmanifest.jsonとサーバから取得したmanifest.jsonを比較して必要なものだけをダウンロードしてlocalStorage/WebSQL/IndexedDBなんかに保存する感じです。これの目的は「通信を抑える」「キャッシュをフルコントロールする」という二点だと思います。特に後者はブラウザ任せにしてしまうと、特定のファイルだけキャッシュアウトさせるというのができなくてぐぬぬとなってしまいます。

Doublerというエンコードも紹介されていましたが、僕の頭じゃ原理はよくわかりませんでした><でもBase64に比べて200%〜250%の圧縮率が高いということで是非使ってみたいです!

Webフロントエンドのレンダリングパフォーマンスと最適化Tips

@さんがパフォーマンスの3大要素「ローディング」「JS実行」「レンダリング」のレンダリングについてお話されていました。

レンダリング時のWebKit内部のフローとChrome DevToolsでのイベントの見方が紹介されていました。ただ、内部のフローとDevTools Timelineのイベントがどれがどれに当たるのかというのが省略されています。僕の理解だと

  • DOMとCSSOMを合体させてRenderTreeを作る部分:RecalculateStyle
  • BOXモデルを画面上に配置して実際のサイズや位置を計算する部分:Layout
  • 数値で指定されている装飾を実際の色や位置に変換する部分:Rasterize
  • 色を描画する部分:Paint

という感じかと思います。もし間違っているところがあれば教えて下さい。

Skiaというツールを使ったペイント時の負荷を紹介されており非常に面白かったです。この部分の処理時間はTimeline上のどこに現れるかというとRasterizeという部分に現れるはずです。border-radius、box-shadow、gradientというのは連続的な色の変化を始点・終点の数値を使って指定します。ブラウザはこの指定された始点と終点を使って実際に表示される色は何色なのか、周りの色との合成というのを計算しなければなりません。この部分の処理が複雑になってくるとペイント時の負荷が上がってしまい、なめらかな描画ができなくなるんじゃないかなと思います。dotted-borderがそんなに負荷が高くなかったのは計算が比較的容易だからでしょうね(補完する必要がないただのベタ塗りで実現できるため)

後半のCaseStudyではGPU処理時の巻き込み事故というのを紹介されていました。これはGPUを使った処理(transform、opacityなど)を行った時に不要な要素までGPU処理の対象になりカクつくというようなものです。これを回避するために対象の要素のスタッキングコンテキストを分離して巻き込み事故をなくすというテクニックが紹介されていました。スタッキングコンテキストについての説明もすっ飛ばされていたんですが、簡単に言うと「他の要素のレイアウト(位置、サイズ)に影響を与えない独立したレイアウト情報」という理解でよいかと思います。例えばposition:absoluteを指定するとその要素はスタッキングコンテキストを生成することになり、レイアウト的に独立したものになります。このようにスタッキングコンテキストを生成することでその要素のみがGPUに転送されるようにして回避できるというお話でした。 詳しくは以下のページで。 https://developer.mozilla.org/ja/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context

個人的にはTimelineは結構見れるようになってきたので、次はchrome://tracingを使ってみたいのですが、複雑で良くわからんという感じです。是非tracingの使い方を解説してほしいです(Skiaとtracingって関係あるのかな?)

Web をまともにしたいので Shadow DOM と Web Components をつくってます

@さんが現在策定中のShadow DOMとWeb Componentsのお話をされていました。

WebComponents、めっちゃ良さそう!タブやボタンを作りたいだけなのに何個もDivを書くのもうイヤです。構造、装飾、振る舞いをまとめてコンポーネント化して再利用できるなるのを待ち望んでいました!さらにWebComponentsがすごいのはCSSのスコープをもつ点。利用している側のドキュメントから基本的にスタイルを操作できなということ(キャットセレクタというので指定することは可能)。WebComponentsはオブジェクト指向を元に考えられているということなのでカプセル化(外部からWebComponents内部にアクセスできない)・包含(WebComponentsは他のWebComponentsも含むことができる)が実装されているようです。後は継承ができればいいのになーという感じです。

で、この話を聞いていて「モバイル時代のフロントエンド開発レシピ」の最後に書いていた思想そのものだ!と興奮していました。このWebComponentsが広く使われる世界が早くこないかなーという気持ちでいっぱいです。

あとShadow DOM、Light Tree、Tree of Treeなど名前が格好いいです(*゚∀゚)

Knockout による大規模 JavaScript 開発 (スペシャルセッションのLT)

@さんがKnockout.jsという双方向データバインディングを持ったフレームワークを使ったゲーム開発のお話をされていました。

発表者のFirefoxOSで有名な飯塚さんとは件のゲーム開発時に一緒に開発をしておりました。資料中の16世紀フロントエンド開発に関するお話は非常にためになるお話でした。

僕個人のknockout.jsに対する感想としては

  • 双方向データバインディングが非常に便利で書き味がよい
  • 薄いフレームワークなので学習コストが低くて良い
  • ただしモバイルで使うにはパフォーマンスが厳しい

と言った感じです。

とりわけ最後のパフォーマンスについてはなかなか苦労します。正確なデータは手元に無いのですが、20~30個程度のバインディングで300~400ms程度かかってしまったと記憶しています(正確なパフォーマンスは別途記事にしたいと思います)。双方向データバインディングだとAngularJSが最近はすごく流行っているようなのでこちらはモバイルでのパフォーマンスはどうなのかというのも知りたいところです。

まとめ

非常に面白い話がたくさん聞くことができ、すごく充実した1日でした。発表者の方々は本当にレベルが高くて、自分はまだまだだなーというのをひしひしと感じました。特に興味を引かれたのはフレームワークやツールうんぬんというよりもパフォーマンスチューニングや不具合回避にのところです。これは直近仕事で苦労しているところだからですね。僕も来年のHTML5 Conferenceで発表できるぐらいに成長したいなー。

こんなに長い記事を最後まで読んでいただきありがとうございました。もし何か気になることがあれば気軽に@までメンションください。