ABEMA で Web フロントデベロッパーとして活動している 宮代 @3846masa です。CyberAgent Advent Calendar 2021 4 日目は、Web パフォーマンス改善のコンテストについてお話します。

TL;DR

  • Web パフォーマンス改善コンテスト “Web Speed Hackathon 2021 mini” を開催します!
  • オンライン開催で、12 月 4 日から 1 月 3 日までの 1 ヶ月間、好きなときに誰でも参加できます
  • 記事の後半は、課題となる「重たい短文投稿サイト」を作るまでの開催記です

はじめに

CyberAgent では、Web パフォーマンス改善を競うコンテスト “Web Speed Hackathon 2020” を昨年開催しました。そして、社内外から大変好評をいただきまして、2021 年も 2 月 6 – 7 日に学生採用イベントで、5 月 13 – 14 日 に社内で、第 2 回を開催しました。

前回同様に、チューニング対象となる激重 Web アプリのコードは、GitHub に公開しています。しかし、GitHub に公開されていても、なかなか試そうというモチベが上がらないのも事実です。

せっかくならば、学生や社員に限らず Web に関わるみなさんにも遊んでいただきたい。そこで、オンラインで Web Speed Hackathon 2021 mini を開催することにしました!

記事の後半には、開催記「Web Speed Hackathon 2021 の作問から開催まで」もありますので、最後まで読んでいただければ幸いです。

Web Speed Hackathon 2021 mini

“Web Speed Hackathon” は、非常に重たい Web アプリをチューニングして、いかに高速にするかを競う競技です。百聞は一見にしかず、まずは課題となる Web アプリを触ってみてください。

https://web-speed-hackathon-2021.herokuapp.com/

今回のテーマは “SNS” アプリ。某青い鳥のサービスに似た短文投稿サイトになっています。つぶやくのはもちろん、画像や動画・音楽の投稿ができます。

ホーム画面
ログイン画面
ユーザー画面
利用規約

トップページを Lighthouse にかけると、何も手を入れていない状態で 3 – 5 点を叩き出します。機能は充実していますが、いかんせんすごく動作が重たい Web アプリになっています。

この Web アプリを改善して、いかに Lighthouse で 100 点に近づけられるか、競います!

Lighthouse でトップページを計測した結果

開催概要

  • 開催期間
    • 2021/12/4 (土) – 2022/1/3 (月)
    • 開催期間中の好きなときに参加できます
    • 冬休みガッツリやってもよし、地道にコツコツやってもよし
  • 参加資格
    • どなたでもオンラインで参加できます
    • 参加登録には、GitHub アカウントが必要です
    • リーダーボードから参加登録できます
  • 参加方法
  • 注意事項
    • GitHub issue による参加登録フローであるため、GitHub アカウント名が一般に公開されます
    • 既に学生採用イベント・社内イベントで開催している都合上、優勝賞品はありません
    • 開催期間が長期間であるため、計測がうまく行かない場合の対応は、ベストエフォートになります
  • 備考
    • 測定結果や解説記事をぜひ #WebSpeedHackathon でつぶやいてください 🤗
    • 開催中に解説記事 / やってみた記事を書くことを推奨します! 他の人の解説を読んでから挑戦するのもありです!
    • 後日、公式にも解説記事を公開します!お楽しみに

作問者(@3846masa)も参加しています、超えてみてください 💪 みなさんの挑戦をお待ちしています!

Web Speed Hackathon 2021 の作問から開催まで

作問テーマの選定

前回の社内向け Web Speed Hackathon 2020 で優勝して、前担当者から「優勝した人が作ってくれると嬉しいなぁ」と打診を受けました。このときは、「アプリケーションを 1 から作るの楽しそう」ぐらいの軽い気持ちで、二つ返事で引き受けました。

作問するうえで一番大きな問題は、「前回と異なる Web アプリを作る」ことでした。前回の解説記事は、広く汎用的に使えるノウハウがまとまっていて、基本的なパフォーマンスチューニングはこなせてしまいます。

前回には登場しておらず、パフォーマンスに大きく影響があるものを考える必要がありました。いろいろ検討した結果、 『メディア』 をテーマに作問することにしました。

パフォーマンスの話になると、動画や音声、Web フォントなどは敬遠されがちですが、リッチな Web 体験を作るためには切り離せないものです。諦めて切り捨てるのではなく、いかにして両立させていくかが問われる問題を目指すことにしました。

アイデア出しのメモ

重たい Web アプリを作る障壁

課題の Web アプリは、最終的に Lighthouse 0 点を目指してデチューニングしていきます。しかし、アプリケーションを組みながらデチューニングすると、開発効率が著しく悪くなっていきます。一旦、ベースのアプリをある程度完成させてから、デチューニングを進める流れで実装を進めました。

一方で、アプリケーションを作り上げてからデチューニングすると、遅くする余地が生まれないこともあります。普段の仕事ではベストの構成を考えて開発するので、いつも通りに組んでしまうと、「この構成だと、どうあがいても重たくならないな…」ということになってしまいます

極端な例で言えば、Next.js や Nuxt.js のような最適化機能が多く積まれたフレームワークは、使うだけでそれなりのパフォーマンスを発揮できます。Lighthouse 0 点を目指すには、常に「どうやってデチューニングするか」を考えながら、アプリケーションを実装する必要がありました。

いくら重たい Web アプリを作るといっても、最終的には高速に動くようにする競技ですので、想定解を考えながら実装することも重要です。例えば、API からデータを取得するコードは、のちに SSR することも視野に入れて、代替しやすいように有名なライブラリのインタフェースに合わせて設計しています

最後にデチューニングを進めるのですが、やりすぎるとそもそも開発できなくなることがあります。とある処理を重たくなるようにした結果、ブラウザのメモリが足りなくなってサイトが落ちる、なんてこともありました。開発できないレベルまで重たくしてしまうと、競技として成り立たなくなってしまうので、塩梅を考えるのも難しいところでした。

サイトが重たすぎてメモリ不足になって焦っている状態

「解きたい」と感じるアプリケーションを作る

私が一番力をいれたことは、「解きたくなるアプリケーションをつくる」ことでした。いかにも競技用に作られたアプリケーションだと、どうしても「実践でも使える」という実感が湧きづらいです。Web Speed Hackathon は、学生採用イベントとして開催しているため、いかに学生に「実務でも使えるノウハウ」を感じてもらうかが大切です。

半分ほどは私自身の趣味ではあるのですが、今回の課題は少しやりすぎなくらい多機能になっています。例えば、動画や音声をアップロードしたときの変換処理が組み込まれていたり、音声からは波形とメタデータを抽出して見栄え良くしたりしています。

音声プレイヤーに波形とメタデータが表示される

また、実際のモックデータもしっかりと用意しました。コードは公開する予定だったため、ライセンス上問題がない画像や音楽・動画を探してきて、より「プロダクトらしさ」のあるアプリケーションを目指しました。画像は Unsplash 、音楽は FreePD 、動画はみんな大好き Big Buck Bunny を使っています。利用規約ページの文言は、Web サイトの利用規約 のテンプレートを拝借しています。

気持ちよく解けるための配慮

競技のコードには解きやすくなる工夫を凝らしています。競技に参加する人は、競技のコードを初見で把握して開発する必要があります。そのため、読みやすい「一貫性のあるコード」を心がけて実装しました

一貫性をどこで生み出すのか、という話ですが、目に見えてわかりやすいところで言えば、コーディングスタイルが挙げられます。例えば、今回は CSS プロパティや JavaScript のオブジェクトのプロパティ、インポート文を、アルファベット順に並べました。また、Tailwind CSS を採用したため、クラス名も特定のルールに則ってソートしました。

ライブラリとローカルファイルでブロックをわけてアルファベット順にインポート文を並べる

一方で、これらの Linter や Formatter が有効になっていると、書き方が強制されてしまい、気持ちよくコードを書くことができません。競技時間が限られているなかで、そのような煩わしさはなくしたいです。そのため、参加者に渡すコードには Linter や Formatter の設定は入っていません。

今回の課題で TypeScript ではなく JavaScript を採用した理由も同じです。とはいえ、いまや TypeScript で開発することが主流になりつつあり、型定義がまったくない状態で開発することも体験が悪くなります。TypeScript では、JSDoc による型情報でもある程度の補完が効くため、できる限り型補完が効くように、JSDoc で型情報を書くことを心がけました。

JSDoc によって型情報が補完されている

開催 1 週間前に起きた Web フォントのバグ

今回は Web フォントを独特の配信形式にして、「とりあえず Google Fonts 使っとけば優勝」をなくしたいと考えていました。そのため、ライセンス上公開できて、視認性も高い 源暎エムゴ を Web フォントに変換して使っていました。

ところが、開催 1 週間前に運営メンバーで確認したところ、文字がぐちゃぐちゃになる現象が起きました。私の開発機では正常にレンダリングできていたため、非常に困惑したことを覚えています。

macOS Catalina / Mojave で起きたフォントのレンダリングバグ

いろいろ調べた結果、ブラウザ起因のバグではなく、OS に起因するバグでした。どのブラウザを使っても、 BigSur 以前の macOS では、特定のフォントのレンダリングがおかしくなるとわかりました。ちょうど私は BigSur にアップデートしたばかりの時期で、他の運営メンバーがまだ BigSur 以前の macOS だったために、偶然気づけました。

結論として、フォントデータの変換処理に一手間加えることで、正常に表示されるようになりました。具体的には、一旦 FontForge でフォントを再出力したあとに、fonttools で Web フォントとして書き出しています。何が原因だったのか調査までできていませんが、なんとか解決して本番を無事迎えることができました。

開催を終えて

今回の課題 Web アプリはいろいろな要素を詰め込みまくっていて、2 日間の競技時間内に想定されるすべてのチューニングを終えるのは至難の業だと思います。かくいう私も、まだすべての解説を書き上げきれていないため、少し要素を盛りすぎたなと若干反省しています。

そんななかでも、学生向けに開催したときには、満点 720 点中 600 点超え、飛び抜けて高いスコアを出す学生がいて、正直驚きました。作問者の私が想定していたチューニング項目のほとんどをこなしていたので、とても悔しかった覚えがあります。

ほとんどが200点台止まりのなか、ひとりだけ600点台を叩き出している

機能落ちでランク外ではありましたが、社員でも 500 点台を出していた社員もいました。結果からみると、頑張れば高いスコアを目指せる、噛めば噛むほど味のある良問になったのかなと思っています。社内で開催したときのアンケートでも満場一致で「難しかった」とのコメントをいただいています。ありがとうございます。

そんな高難易度のパフォーマンスチューニング、やってみたくありませんか?ぜひこの 12 月に Web Speed Hackathon 2021 mini に挑戦してみてください。

2022 年 1 月ごろに解説記事とともに結果発表できればと考えています。みなさんの挑戦をお待ちしております!また 1 月にお会いしましょう!