こんにちは。 一休.comの開発基盤を担当しています、akasakasです。
今回は、一休.comスマートフォンホテルページリニューアルをリリースし、パフォーマンスが改善したお話をさせて頂きます。
UI部分は既存を踏襲する形をとり、UX・パフォーマンス改善にフォーカスして、所々で様々な工夫をしました。
お話ししたいことが盛りだくさんなので
- 概要編
- JavaScriptパフォーマンス改善編
- CSS・その他細かいチューニング編
- サーバサイド編
の4つに分けて、お送りしたいと思います。
この記事ではスマートフォンホテルページリニューアルの全体像についてお話しします。
詳しいお話をする前に:スマートフォンホテルページってどこ?
こちらになります
https://www.ikyu.com/sd/00001290/
ここでお話しする内容
- リニューアル前後のパフォーマンス比較
- PageSpeed Insights
- Audits
- Calibre
- パフォーマンス改善が必要だった理由とリニューアルの背景
- ASP.NET Web Forms(VB.NET) → ASP.NET MVC(C#) へのアーキテクチャリプレイス
- 宿泊スマートフォンサイトが抱えていた大きなボトルネック
- Time To First Byte
- レンダリングブロック
- 肥大化したJavaScript・CSS
- それぞれの課題に対する解決策とアプローチ
- まとめ
リニューアル前後のパフォーマンス比較
PageSpeed Insights
PageSpeed Insightsのスコア比較は以下の通りです。
サードパーティクッキーのキャッシュコントロール以外の項目は解消することができました。
before
after
Audits
Metricの各指標が改善され、指摘事項も概ね解消できているのがわかると思います。
前提
- Chrome 68(Lighthouse 3.0beta)
- Simulated Fast 3G, 4x CPU slowdown
before
after
Calibre
一休ではWebフロントエンドパフォーマンスモニタリングSaasの Cailbre を使っています。
Time To First Byte をはじめとして、各指標が改善されているのがわかります。
before
after
パフォーマンス改善が必要だった理由とリニューアルの背景
Mobile-First Indexなどの理由はあると思いますが、
- 初期表示が遅かった
- 再検索のたびにリロードが走り、遅かった
という点を改善し、ユーザに快適に使って欲しいというところがモチベーションとしてありました。
上記2点を解消する上で障壁となったのが
- ASP.NET Web Forms(VB.NET) によるレガシーアーキテクチャ
- 単純に非同期で読み込むことができないレンダリングブロックしている古のJavaScript
- 上書きに上書きを重ね、7,000行を越えていたCSS(メンテナンス困難)
でした。
宿泊サイトは前回の大規模リプレイスから10年近くと長きに渡って価値を生んでいるサービスなのですが、上記の問題を抱えたままでパフォーマンスを改善し、より高い価値を提供することが難しくなってきたという背景がありました。
これを機会にスマートフォンホテルページのみ部分的に新しいアーキテクチャでリプレイスをしようという決断をしました。
ASP.NET Web Forms(VB.NET) → ASP.NET MVC(C#) へのアーキテクチャリプレイス
一休.comのほとんどはVB.NETでシステムが構築されています。
ASP.NET Web Formsベースの独自フレームワークです。
大規模リプレイスをしたのが2009年頃なので、宿泊サービスを10年弱支えてきてくれました。
ここまでのお話を聞いて頂ければ、色々と察してくださる方も多いと思います。
上述の通り、パフォーマンス面での性能・UX改善が難しくなってきたという背景から、 ASP.NET C# へのアーキテクチャリプレイスを一部実施しました。
過去の学びから大規模リプレイスはやめて、薄いコンポーネントだけ被せる、MVC の作法に則る形をとるようにしました。
ここは宿泊システムのレガシーアーキテクチャ改善を進めてくれた @shibayanに基盤を作ってもらいました。
補足:ASP.NET Core MVC (.NET Core)を選ばなかった理由
「なぜ、ASP.NET Core MVC (.NET Core)を選ばなかったのか?」と疑問に思われる方もいるかもしれませんので、補足しておきます。
- 既存のFramework/Componentsを使う必要があり、そこの互換性が.NET Core だと対応してなかった(主に認証に関わる部分)
- Web forms を捨てることにスコープを置いた
- これまでのアーキテクチャ改善によって DB アクセス周りや新しい処理は C# へのリプレイスが進んでいた
- プレゼンテーションレイヤーだけC#で書けない状況を打開することに注力した
- パフォーマンス改善の文脈とは別にアーキテクチャ改善に重きを置いていたプロジェクトが先行して走っていて、スマートフォンホテルページリニューアルがそのパイロットプロジェクトとなった
という経緯があります。
宿泊スマートフォンサイトが抱えていた大きなボトルネック
アーキテクチャリプレイスだけで、万事解決!!!というわけではなく、他にもパフォーマンス面で抱えていた課題がありました。
上記でも簡単に触れましたが、宿泊スマートフォンサイトが抱えていた大きなボトルネックは以下になります。
Time To First Byte
複雑なSQLをいろんなところから複数回呼び出すような処理が散乱していました。 このため、Time To First Byteが遅かったです。 また、ASP.NET Web Forms(VB.NET)の独自フレームワークでは非同期処理の実装が難しかったという側面もあり、これもTime To First Byte悪化の一因でした。
レンダリングブロック
古のJavaScriptに悩まされ、単純にdefer/asyncを使った非同期読み込みができず、Critical Request Chainが長くなり、ページスピードを下げる一因となっていました。
before/afterでのCritical Request Chainの長さを見れば、一目瞭然だと思います。
before
after
肥大化したJavaScript・CSS
上述の通り、肥大化したJavaScript・7,000行越えのメンテナンス困難なCSSがあり、これもまたページスピードを悪化させている要因の1つとして大きかったです。
before:JavaScript転送量
ちなみに、画像転送量と同等のサイズでした。
after:JavaScript転送量
7000行越えのCSS
それぞれの課題に対する解決策とアプローチ
Time To First Byte
- ASP.NET MVC C# により、非同期処理の実装が容易にできたこと
- データ取得処理は、検索APIの一か所にまとめてasync/awaitで取得
- 検索APIの呼び出しもasync/await
- 鮮度を問わないデータはElasticaheでキャッシュ
というところで、Time To First Byte改善につなげました。
詳しい話はサーバサイド編でお話しできればと思います。
レンダリングブロック
ASP.NET MVC C# リプレイスに乗じて、古のJavaScriptたちも全て捨てました。
- Vue.jsに寄せ、必要な箇所はコンポーネント化
- async/deferで非同期読み込み
- bodyタグの末尾でJavaScriptの読み込み
などでレンダリングブロックを解消し、Critical Request Chainを削減し、パフォーマンス改善ができました。
詳しくはJavaScriptパフォーマンス改善編でお話しできればと思います。
肥大化したJavaScript・CSS
上記に対しては
- JavaScript
- dynamic importによる初期ロード時のリソース削減
- 遅延レンダリングによるJavaScript実行時間の削減
- CSS
- インライン展開
- loadCSSを使った非同期読み込み
- FLOCSSを採用
- 不要なCSSセレクタの削除
を実施しました。
至極当然ですが、無駄なJavaScript・CSSをなくせたこともパフォーマンス面でけっこう大きいのかなと思いました。
詳しくは
- JavaScriptパフォーマンス改善編
- CSS・その他細かいチューニング編
でお話しできればと思います。
まとめ
一休.comスマートフォンホテルページリニューアルをリリースし、パフォーマンスが改善したお話をさせて頂きました。
単純にレガシーシステムからリプレイスするだけでパフォーマンスが劇的に向上するわけではなく、ちゃんとボトルネックを理解した上で改善しなければ、同じ轍を踏みかねないということを学ぶことができたのは個人的に大きかったです。
また、今まで長い間頑張って価値を生み続けてくれた既存のシステムには感謝と敬意を払いながら、未来のために新システムに切り替えていきたいです。
今回、お話しした内容はあくまでも概要であり、サーバサイド・フロントエンドそれぞれの深いところのお話しは次回以降、お話しできればと思っていますので、ご期待ください。