ベストなユーザエクスペリエンスを実現するJavaScriptの課題と可能性

https://www.youtube.com/watch?v=p2F-128e3sI

1 comment | 2 points | by WazanovaNews 3年弱前 edited


Jshiike 3年弱前 edited | ▲upvoteする | link

Socket.ioのクリエーターとして知られるGuillermo RauchのBrazilJS 2014での講演です。理想のシングルページアプリをつくろうとすると、JavaScriptが損なってしまうケースはあるとしながらも、一方で、多いに可能性を感じさせるトレンドもあるとして、最優先であるユーザエクスペリエンスを向上させるポイントを紹介しています。

1) 課題

  • スクリプトやCSSにブロックされることで、レンダリングの際にブランクページを表示してしまう。
  • Webスクレイピングというコンセプトを壊してしまう。サーバレンダリングしない限りは、フロント側はスムーズにスクレイピングをできるが、その間は誰もページにクエリしてhttpを分析できない。ポーリングしてデータがあるかどうかの確認も必要になり、クライアント側でやると、システムからのデータの抽出がすごく複雑になる。
  • サーバ側でテストがしづらい。
  • バックボタン
  • リアルタイムで、レスポンスが早いシングルページアプリにおいては、ユーザがクリックする度にページを再読込みしているわけでないので、どうやってタイミングよく、コード変更をユーザに通知できるか。バックエンドのコードの変更を、実行中のフロントコードとどう同期させるか。

2) フロントエンドとバックエンドのハイブリッドレンダリングを採用すべき

  • フロントエンドのJavaScriptエンジニアにとってサーバサイドのレンダリングは、いつかそのうち対応しようというようなオプションではない。ユーザエクスペリエンスを最適化するためには、ハイブリッドなソリューションが必ず必要になる。
  • ベストなユーザエクスペリエンスのためには、とくかくスピード。パケットをやり取りする際のサーバとの距離はどうしようもない。自分たちにできるのは、ラウンドトリップ回数を最小化すること。また、Ilya Gridorikの唱えた、最初の14KBの読込みを最適化することも重要。
  • ものすごくバックエンドが早くて、サーバの位置もユーザに近く、CDN使って、14KB対応もできれば、フロントエンドのJavaScriptはなくていいのではと勘違いするケースもあるが、そうではない。フロント側のJavaScriptでしかできない役割もある。
    • ブラウザは進化しても、webプラットフォームの仕組みはそれほど変わっていない。レンダリング、ヒストリー管理、ブラウザ/サーバ間のやり取り、再読込みボタン、リンクがどう機能するかという仕組みは変わってない。
    • ユーザのインプットに即座に反応することは、クライアント側にJavaScriptを実装しないとできない。
    • 遅延を隠すマスク操作をすることで、サイトのレスがものすごく早いとユーザに思わせることができる。JavaScriptは、何が起きるか準備しておいて即座に処理できる。

3) フレキシブルにレイアウトを順応させる

  • Facebookはページ起動の際、サーバからコンテンツを受取る前にまず画面にプレースホルダをだす。そこから、並列処理を工夫して、ニュースフィード => 広告という優先度で表示していく。ニュースフィードで取得するコンテンツのサイズまでは事前に把握してないので、最終的には表示枠が小さくなったり、大きくなったりする。Pinterestの場合は、まずは表示するコンテンツのサイズと色を把握。取得する写真の平均の色を計算して、実際に表示される前に、平均の色と正しいサイズのプレースホルダをだす。iPhoneも当初、default.pngをまず表示することを推奨していた。いずれも、ユーザに遅延を感じさせないマスク効果を狙ったもの。
  • PNGファイルをユーザがアップロードするときに、フロントエンドのJavaScriptがヘッダー情報からサムネイルを生成しページに表示することで、既にアップロードが完了した印象を与えることができる。初期のwebは、アップロードしたらしばらくページで何も起きない。次に、進捗バーを表示するようになり、今や、ファイルを事前処理するところまで進化してきた。
  • スピードは、実数だけでなくユーザがどう認知するかというのが大事。ユーザに幻覚を見せることで、技術的な限界を隠す。Steve Soudersが紹介していたように、ボストン空港は、荷物受取りのコンベアレーンの長さを6倍に延長することで、「レーンが何度もぐるぐるまわってるが、自分の荷物はなかなか出てこない。」という顧客の感覚を減らすことに成功したが、同じ効果を狙ったテクニックが使える。
  • 但し、支払完了は正確に伝えるべきだし、ログアウトも、本当に完了したとユーザ勘違いして端末を離れた後に、他人に画面を操作されると危険。センシティブな場面では、マスク効果を使ってはいけない。
  • ニールセンの調査によると、1秒を過ぎるユーザはリアルタイムでやり取りしていると感じなくなる。もしスピナーを表示するのであれば、1秒を過ぎてから。

4) どのデバイスでも常に同期させる

  • Socket.ioを開発した目的がこれ。
  • PC/タブレット/携帯とデバイスが多様化し、オフィス/家庭などあらゆる利用シーンがあるので、同期しなくてはいけないデータポイントは増えている。ゆえに、同期の重要性は上がっている。自動的に画面が更新することで、ユーザに再読込みボタンを押させない仕組みにすべき。
  • ログイン/セッションステートの同期は、プライバシーの向上という観点からも大切。銀行口座を操作する画面をログアウトしたら、すぐにどのデバイスでもホーム画面にすぐ同期させたい。
  • ネットワークの再接続時にスムーズなユーザエクスペリエンスを提供できてないケースも多い。作業中のPCを閉じた後、携帯で続きの操作をしながら、PCを再度開いた際は最新の内容が即座に反映されているべき。
  • 一方で、常に最新のコンテンツを取得できるポーリングには副作用がある。コンテンツの更新ボリュームが多いサービスでは、際限なくアップデートされる。「さらに読込む」というボタン/リンクを適宜表示して、ユーザ側が閲覧の際に調整できるようにすべき。
  • サーバ側でHTMLをレンダリングし、クライアントに到達するまでの間はオフラインと同様だと見なすことができる。その間にデータが変更になっている可能性もあるから。JavaScriptを介して継続的な接続を確立するとよい。

5) クライアント/サーバ間のやりとりをコントロールできるようになった

  • 従来からのwebにおけるデータのやり取りのパターンは三つ。
    • クリックすることによるgetでの取得
    • フォームに入力した内容をpost
    • オブジェクト、サウンド、画像のダウンロード
  • このデータ取得のタイミングをコントロールする最初のハックは、極小のピクセル画像によるユーザアクションの計測。JavaScriptで自動化できるようになった。一番簡単な手法であるゆえ、かつてFacebookのページの特定の箇所全てにインラインで埋め込まれていた。その後、iFrame、AJAX、ActiveXオブジェクト、XmlHttpRequest、バイナリデータサポート、サーバ送信イベント、websocketと進化してきた。
  • 自動的にアップデートするUIになれば、オンライン/オフラインを確認できることが、ユーザの期待値になる。

6) オフライン対応、セッション管理とデータの同期

  • オフライン対応と再接続後のデータ同期には、サービスワーカーAPIが役に立つ。ローカルストレージにデータがあれば、ワーカーがブラウザのバックグランドでネットワークリクエストをする。また、アナリティクスと連携した非同期のトラッキングにも利用できる。
  • 接続が切れた後の自動再試行をユーザに替わってやるのがwebアプリ側の責任。
  • セッションが期限切れした場合は、メッセージをだしたあり、ログイン画面に遷移させたり、スムーズにユーザに通知する。Gmailのように、送信中に画面を閉じようとするユーザに警告をだす仕組みは親切。beforeunload eventで実装できる。
  • 履歴管理の改善は重要。fast backと呼ばれる、直近ページのキャッシュを保持し、ユーザが戻ってきたときにすぐにキャッシュを表示する。履歴記録が相対変化を管理できる機能が必要。今はレンダリングし直したりして、ユーザエクスペリエンスを損ねている。
  • ロールバックメモリ: スクロールポジションを記憶するか、関連のあるページの部分を履歴管理して、戻った時に適切な表示をする。サーバ側でのレンダリングでは、urlからきっちりした管理ができたが、フロント側ではうまく処理できていない。
  • 一時的な変更はローカルメモリを利用して、履歴管理する。例えば、Redditにおいて、表示が隠れているコメントツリーを開いた後に、別のページにリンクをたどって、また戻ってきたら、元の状態を記憶しておいてくれない。

7) コードのアップデート機能

  • 1年間ページを再読込みしないままのユーザのフロントコードもうまくアップデートしたい。例えば、
    • socket.ioのイベントを送って更新する。
    • スクロールがページの先頭にあって、動いていないとわかるなら、ユーザに替わって更新する。
    • タブを移動したことを検知して、裏側で更新する。
  • バックエンドが、フロントエンドのコードのバージョンを把握して処理しなくてはいけないケースがある。ヘッダーにその情報を入れて送ることで対処したことがある。デバッグの際にも役立つ情報になるはず。
  • ライブでコードを再読込みしたい。例えば、Reactは、バーチャルに都度レンダリングし、実際のDOMとの差分だけを反映しているが、このような仕組みを応用すればコストをかけずに必要な更新をするフレームワークをつくれるかも。
  • ユーザの振る舞いを予想する仕組みも有効。
    • ボタンの上をカーソルがhoverすると、アクションを予想して準備する。
    • クリックイベントの替わりにマウスダウンイベントをトリガーにする。
    • マウスインプットの進む角度を把握し、ユーザが次にアクションする箇所を予想する。

8) Q&A

  • Meteorのホットコードリロードの仕組みは詳しくは把握していないが、Reactのコンセプトに近いことをやってると思う。副作用として全体をシンクさせるのでスピナーが表示されるが、その後はスーパー早く反応する。React的なテンプレートエンジンも採用していて、色々最適化を試みているところだろう。
  • 今いちからシングルページアプリをつくるなら、各ページの目的を慎重に考慮する。ユーザが目的とするコンテンツの表示が最優先。全てのページでは対応できていないことが多い。Paul Irishのプレゼンで指摘されていたimgur.comのように、猫の写真を見たいユーザに対し、フレーム/コメント/タイトル、そして写真という順で表示するのはよくない。写真を先に表示しないと。自分も、PDFの最初のところだけを先に取得するなど、工夫できるところはしている。

#javascript #シングルページアプリ #サイトパフォーマンス


ワザノバTop200アクセスランキング


Back