こんにちは、フロントエンドエンジニアの原(@herablog)です。今日はアメーバニュースモバイル版(モバイル端末でご覧ください)のリニューアルをご紹介したいと思います。

労力と効果

Webがサービスとして利用されるようになってから、長い月日を経てさまざまな構成パターンやライブラリ・フレームワークが生み出されました。今では作りたいものはなんでも作れるといっても過言ではないでしょう(いや、やっぱり大げさかもしれません)。そんな中で我々は労力に対して効果がより得られるポイントを探り出す必要があります。今回のアメーバニュースモバイル版のリニューアルでは、そのような考えから始めてみました。

労力と効果の均衡点を探って、定時あがり(エンジニアを褒めるネコのイラスト)
エンジニアを褒めるネコ、いつもありがたく使わせていただいております。

サイトの前提条件

どのような構成のWebサイトにするかを選択する上では、前提条件を確認・定義することが大切です。それによって選択される結果は変わってくるでしょう。

アメーバニュースにおける前提条件は以下のようなものでした。

  • 読み物(テキストメイン)コンテンツである
  • サーチエンジンや各種クライアントなどへのマシンリーダビリティの担保が好ましい
  • 記事ページへの流入が大半である
  • 記事は1回読み切りのようである
  • サイト内回遊性はあまり高くない
  • アクセスはほぼ日本国内から
  • サイト規模からメンテナンスに多くのメンバーは割けない

などなど

パターンの選択

Webサービスの構成パターンとしては、Single Page Application (以下SPA)、Isomorphic Web Application (以下Isomorphic)、Traditional Web Application (以下Traditional)が挙げられます。

SPAは、ほとんどの処理をクライアント側で行います。ページという概念にとらわれず、Webサイト(アプリケーション)を作ることができます。エディタなど操作系のリッチなアプリケーションを作るのに向いています。非常に魅力的な仕組みですが、読み物系である今回のアメーバニュースの前提条件には合いませんでした。

Isomorphicはサーバー側・クライアント側どちらでもレンダリングできるようにする仕組みで、初期表示・ページ遷移どちらも高速です。フロントエンド・バックエンドを統合して非常にクオリティの高いサイトを作成することができます。アメブロはこの形で実装されており、労力に対して大きな見返りを得ることができました。ただし、少し上級者向けです。このパターンが本当に必要かよく考えて導入する必要があります。

TraditionalはWebサイトが作られ始めた頃からあるURLに対してHTMLをレンダリングして返却する仕組みです。HTTPリクエストに対して一意のリソースが返却されるため、仕組みは簡単です。その反面、サーバーサイド・クライアントサイドが分断されがちで、SPAやIsomorphicのような優れたユーザー体験を実現するのは大変です。

ニュースという前提条件からサーバーサイドでのHTML生成をデフォルトで備えたIsomorphic, Traditionalパターンに絞りましたが、今回は比較的作成が容易なパターンであるTraditionalで、早いHTML中心のサイトを作ったらどうなるかといったチャレンジをしてみることにしました。

静的コンテンツと動的コンテンツ

Webサイトには静的コンテンツと動的コンテンツがあります。静的コンテンツはHTTPリクエストに対して、常に一定のコンテンツです。例えば記事の中身が該当します。対して、動的コンテンツはUser agentやCookieなどに含まれるユーザー属性によって変化するコンテンツです。

アメーバニュースでは、記事の内容を静的コンテンツとしてHTMLに含め、おすすめコンテンツやランキング情報などは動的コンテンツとしてクライアント上でデータ取得、表示をしています。このように、静的コンテンツと動的コンテンツを分けると、効率的にキャッシュを活用できるようになります。

記事ページのスクリーンショット。ページ上部の記事は静的コンテンツとしてHTML内に埋め込み、ページ下部の動的コンテンツはXHR取得で表示。

CDNとキャッシュ

URLに対するHTMLの内容が静的になると、再利用性があがり、都度レンダリングする必要がなくなります。今回のリニューアルでは一度WebサーバーでレンダリングされたHTMLをCDNにキャッシュとしてもたせるようにしています。

当然ながら記事の更新はほとんどおこらないので、キャッシュヒット率は非常に高く(目を疑うほど高いです)、サイト内で表示されているほとんどどのリンクを辿ってもキャッシュされています。また、動的コンテンツはAPIとして提供されていますが、こちらも適切なキャッシュTTLを設定することでサーバーでの無駄な処理を省くことができます。

アメーバニュース内ページ遷移の動画。トップページでリンクをクリックし、記事ページへ遷移。
サイト内のリンクはだいたいキャッシュヒットするため、ページ遷移は高速です。
Chrome Dev Toolsに表示されるレスポンスヘッダのスクリーンショット。Server-TimingレスポンスヘッダーにHITという文字が記載されている。
アメーバニュースではServer-Timingレスポンスヘッダーにキャッシュヒットしたかどうか付与しています。
Chrome Dev Toolsに表示されるレスポンスヘッダのスクリーンショット。ETagヘッダーにリソースのハッシュ値が付与されている。
HTMLを効率的にキャッシュさせるためには、サーバーでの乱数やUser agentごとの分岐など一意にならない処理を取り除きます。コンテンツが一意かどうかはETagを生成して確認すると良いでしょう。

パージシステムとデフォルトTTL

できるだけ長い時間のCDNキャッシュは非常に効率的ですが、適切なタイミングで内容を変更できなくなってしまう可能性があります。たとえば、記事の内容が修正されたり、サイトのデザインを変更したりしたい場合があります。

そうした場合にそなえ、CDNキャッシュをパージするシステムを構築しました。管理画面で記事の更新を検知すると、CDNのAPIを通じて該当するキャッシュキーの内容をパージします。サイトのデザインをリニューアルしたい場合には広範囲のコンテンツをまとめるキャッシュキーを利用して更新することができます。

それ以外の、特定キャッシュキーやTTLをもたないコンテンツは、デフォルトTTLが適用され、時間が経つと自動的に内容が更新されます。

パージシステム概要図
パージシステムの概要です。CDNには記事IDをキーにしてキャッシュします。CDNにキャッシュがある場合にはオリジンサーバにアクセスすることなくそのデータをクライアントに返却します。記事が更新された場合にはCDNキャッシュをパージしてデータを更新します。

UIライブラリとしてのAMP

今回のリニューアルでは、AMPをUIライブラリとして使用しています。実は、アメーバニュースでのAMP対応をした際に思いのほかUIを再現できたため、このまま全面的に適用もできるのではないかといったところからスタートしました。

アメーバニュースは静的コンテンツでHTMLを中心にシステムを作ることができ、現在のAMPの仕組みと相性がよいといえます。スクリプトを読み込むだけで利用でき、ビルドシステムがいらないのも利点です。また、比較的厳しいバリデータも備えており、品質を劣化させないように保てます。

ただし、UIライブラリを使わない、もしくは薄いUIライブラリでも実現できることでもあり、サイトの特性に応じて都度選択する必要があります。ここで、便利だったAMP要素をいくつかリストアップしておきます。

  • amp-list 動的コンテンツの表示、要素の遅延ロードを実現できます
  • CLIENT_ID() 特定クッキーの値をリクエストURLに付与でき、セグメントされたデータを提供するのに役立ちました
  • amp-timeago 記事の更新時間を現在時間との比較表示に変更でき、記事の鮮度を表すのに便利でした
  • amp-lightbox 記事画像の拡大ビューに利用しました。
アメーバニュースページ内UIパーツのスクリーンショット。サイドバーや、カルーセル表示、画像ライトボックスなど。
AMPで用意された要素を利用することで多くのモバイルUIパーツを作成できました。

amp-toolbox-optimizer

AMPはサーチ結果向けに最適化されており、そこでの表示では十分に早いですが、AMP boilerplateには visibility:hidden と定義されており、実際には、ベースとなるスクリプト・スタイルの読み込み・評価が終わるまで何も表示されません。

amp-toolbox-optimizerを使うとそのAMP boilerplateを削除し、初期表示に必要なリソースをHTMLに埋め込めるため、アメーバニュースにとって重要だと考えられるFirst Contentful Paintをかなり向上させることができます。

ただし、これを使うとValidなAMPページではなくなるため、サーチ結果のためのページには適用できないことに注意が必要です。また不必要な再レンダリングを割けるためにキャッシュ層(CDN, Memcachedなど)との併用が推奨されています。

amp-toolbox-optimizer適用前後の表示比較動画
amp-toolbox-optimizer適用前後の表示比較。読み込み完了はほとんど変わらないが、テキスト表示が早くなっていることがわかります。ニュースサイトではいち早くテキスト本文が表示されることがユーザー体験向上につながります。

パフォーマンス指標の変化

システムをリニューアルしたことによるパフォーマンス指標の変化をいくつかご紹介します。19日はリニューアル後の数値、23日はamp-toolbox-optimizer適用後の数値です。下記の計測は、SpeedCurveで東京リージョンから4G環境でおこなっています。

H1 Renderの遷移グラフ。リニューアル直後は1.1秒で、amp-toolbox-optimizer導入後には0.3秒。

H1 Renderは、amp-toolbox-optimizerの導入で大きく改善しました。

Start Renderの遷移グラフ。SpeedIndex, Visually Completeの値はリニューアル直後に大幅改善。Start Renderはamp-toolbox-optimizerの導入後に0.3秒に。
リニューアルでSpeedIndex, Visually Completeの値が改善しました。ニュースサイトにとって大事であるStart Renderはamp-toolbox-optimizerの導入で大幅に向上しました。

0.5秒ごとのFilmstrip。0.5秒でテキストが表示され、1秒後に記事画像が表示されます。
0.5秒以内にテキストコンテンツが表示されています。

Start RenderまでのCPU Time遷移グラフ。リニューアル直後にはScript処理が増えたが、amp-toolbox-optimizerの導入後には0秒に。スクリプト、レイアウト、ペイント、ロード、その他、アイドル時間のトータルもamp-toolbox-optimizerの導入後に約三分の一に短縮。
Start RenderまでのCPU Timeはamp-toolbox-optimizerの導入で大幅に改善しました。

Blocking Resorcesの変化。リニューアル前にはスタイルが3つ、スクリプトが10つあったが、リニューアル後にどちらも0に。
AMPの利用で、Critical Blocking Resorcesは0になりました。

今後ありえそうなこと

最後に、今回選択した構成パターンで今後ありえそうな進化を少しまとめてみます。

CDNでのHTML配信は概して安定してパフォーマンスを向上させますが、逆にサーバーパフォーマンスの一部が我々の手から離れてしまったことを意味します。サーバーレスポンスのモニタリングも欠かさずおこなう必要があるでしょう。

App Shellパターンでリソースのキャッシュ・オフライン対応もあるかもしれません。ただし、現状の前提条件ではあまり必要性がない可能性があるほか、処理が増えるので対応方法によってはいくぶん遅くなる可能性もあります。メリット・デメリットを比較して丁寧に導入する必要があるでしょう。

サイトの回遊性は低いとは言え、できるだけ多くのページをみてもらうことはサービスにとって大切です。アクセスログのデータから投機的preferchの仕組みを作りページ遷移での離脱を減らすことができるかもしれません。

また、MPAパターンでサーバサイドとService WorkerでのIsomorphicパターンを試すことができるかもしれません。アメーバニュースモバイル版はHTMLとCSSという宣言的な記述でできているため、相性がいいともいえます。これらもまた、複雑性と効果とのトレードオフで考慮する必要がありそうです。