データをどこで取るか — 取得が一列に並ぶと、画面は足し算で遅くなる
注文の詳細画面が 2.4 秒かかっていた。API はどれも 0.8 秒で返っていた。部品がそれぞれ、自分が描かれてからデータを取りに行っていたので、3 回の待ちが順番に並んでいた。
この記事の進み方
What — 取得が一列に並ぶ仕組み
部品ごとにデータを取る書き方は、とても自然です。部品が自分の必要なものを自分で取るので、部品を別の画面に持っていっても、そのまま動きます。
ただしこの書き方には、見えない順番が入ります。
- 親の部品が描かれ、親のデータを取りに行く
- 親のデータが届くまで、子の部品は描かれない(まだ親が「読み込み中」を出している)
- 子が描かれて初めて、子のデータを取りに行く
こうして、部品の入れ子の深さだけ、取得が一列に並びます。この並びをウォーターフォール(滝)と呼びます。
各部品が、自分が描かれてから取りに行く。
注文 ████████
購入者 ████████
配送状況 ████████
0 0.8 1.6 2.4 秒- 表示まで
- 2.4 秒
- 部品の独立性
- 高い
- 通信の回数
- 3 回
- –入れ子が深くなるほど、待ちが足し算で増える。
- –どの部品も単体では正しく、コードを読んでも遅さの原因が見えない。
API の速さは同じ。取りに行く順番と場所だけが違う。
並ぶべきものと、並ばなくてよいもの
すべての取得を同時にできるわけではありません。前の結果を使って次を取るものは、順番が要ります。
- 注文を取り、その中にある購入者の ID で購入者を取る → 順番が要る(ID が無いと呼べない)
- 注文の番号で、注文・配送状況を取る → 同時にできる(どちらも番号だけで呼べる)
冒頭の画面は、3 つとも注文の番号だけで呼べたのに、部品の入れ子のせいで順番に並んでいました。データの依存ではなく、部品の形が順番を決めていたのが問題です。
冒頭の画面で、取得が一列に並んだ原因はどれですか?
一覧の中で 1 件ずつ取る
もう 1 つの典型は、一覧の各行が、自分のデータを取りに行く形です。
一覧を取る(20 件)
→ 行 1 がユーザーを取る
→ 行 2 がユーザーを取る
→ …
→ 行 20 がユーザーを取る ← 20 回の通信
DB で言う N+1 問題が、ブラウザとサーバーの間で起きています。同時に出すので待ちは足し算になりませんが、通信の回数とサーバーの負荷は行の数だけ増えます。一覧を取るときに、必要なユーザーもまとめて取るか、ID をまとめて 1 回で取るようにします。
Why — なぜ気づきにくいのか
どの部品も、単体では正しい
部品ごとに取る書き方は、部品を独立させる良い習慣から来ています。どの部品を読んでも、おかしな所はありません。遅さは、部品を組み合わせたときに初めて現れます。コードを読むだけでは見つからず、通信の記録を時間の順に見て初めて分かります。
開発環境では待ちが短い
開発者の手元では、API がすぐ近くにあり、データも少なく、1 回の往復が数十ミリ秒で済みます。3 回並んでも 0.1 秒で、誰も気づきません。本番の、遠くて混んだ回線で、1 回の往復が数百ミリ秒になって初めて、足し算が効いてきます。
まとめすぎると、別の払うものが来る
同時にする、1 つにまとめる、はどちらも速くなりますが、払うものもあります。
- いちばん遅いものを全員が待つ。 3 つを 1 つの API にまとめると、配送状況が遅いとき、注文も購入者も表示されない
- 部品が独立しなくなる。 画面の入口やまとめた API が、部品が何を必要とするかを知る必要がある。部品を足すたびに、入口も直す
だから、速くするだけでなく、遅い部分を後から出せる形にしておくことが大事です。注文と購入者を先に表示し、配送状況は届いたら差し込む。描画をどこでするかで見た、部分ごとに分ける考え方と同じです。
注文・購入者・配送状況を 1 つの API にまとめたところ、配送業者の API が遅い日に、画面全体が表示されなくなりました。どう直すのがよいですか?
演習 — まず自分で判断する
解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。
冒頭の注文の詳細画面を、どう直しますか?
- 注文・購入者・配送状況の 3 つの API は、どれも注文の番号だけで呼べる。それぞれ 0.8 秒
- 配送状況は外部の配送業者に問い合わせていて、ときどき 3 秒以上かかる
- 購入者の部品は、ほかの 4 つの画面でも使われている
- 表示まで 1 秒以内にしたい
- · 並びを作っているのは、データの依存か、部品の形か
- · 同時に取ることで、どの部品が何を知る必要が出るか
- · 遅くなりうる取得を、ほかの表示から切り離せるか
「API はどれも 0.8 秒で速いのに、なぜ画面が 2.4 秒もかかるのか」と聞く、バックエンド担当の同僚に説明してください
- 相手は API の性能を測り、問題が無いことを確かめている
- 相手はフロントエンドの部品の仕組みには詳しくない
- 相手に協力を頼みたいこと(画面用の API など)があれば、それも伝えたい
読み終わりましたか?
読了にすると、これを前提とする記事がロードマップで開放されます。