ここまで10回、速くする方法を扱ってきました。この回は逆に、速くしないという判断を扱います。
性能改善は必ず何かとの交換です。EP.1 で「払った代償を書き残す」と書きましたが、そもそも払う価値があるのかを判断する場面のほうが多い。
1. 速さと引き換えに失うもの
この連載で扱ってきた手段は、それぞれ代償を持っています。並べてみると構造が見えます。
| 手段 | 得るもの | 失うもの |
|---|---|---|
| を貼る | 読み取りの速さ | 書き込みの速さ、容量 |
| を入れる | 応答の速さ | データの正しさの保証、複雑さ |
| まとめて取る | 問い合わせ回数 | メモリ使用量 |
| 並列化する | 処理時間 | 複雑さ、デバッグの難しさ |
| SQL を作り込む | 実行時間 | 可読性、分布変化への弱さ |
| 先に用意しておく | 体感の速さ | 無駄になりうる通信 |
2行目が最も重い。キャッシュはデータの正しさを部分的に諦める仕組みです。表示だけなら許容できても、金額や在庫の判断に使うなら話が変わります。速さの議論に見えて、事業上のリスクを取る判断になっています。
並列化や作り込んだSQLは、書いた本人がいる間は問題になりません。効いてくるのは、担当が代わり、仕様が変わり、誰も理由を説明できなくなってからです。そのとき触れなくなることが、複雑さの本当のコストです。
2. やらない判断の基準
判断の材料は、EP.1 で決めた目標値です。目標を満たしているなら、それ以上はやらない。単純ですが、目標がないと成立しません。
- 1目標を満たしているか — 満たしているなら、原則やらない
- 2誰が困っているか — 誰も困っていない遅さは、直す価値が薄い
- 3どれくらいの頻度で起きるか — 年1回の処理を半分にしても効果は限定的
- 4改善で失うものは何か — 可読性か、正しさか、開発速度か
- 5その工数を別のことに使えないか — 機会費用として見る
2番目の問いが効きます。「なんとなく遅い気がする」で始まった改善は、終わりが来ません。誰がどの操作で困っているかを特定できないなら、その改善は優先度が低い。
5番目も現実的な観点です。性能改善に1週間使うなら、その1週間で別の価値を出せないか。目標を満たしている状態からの改善は、機会費用のほうが大きいことが多い。性能の話は技術的に面白く、しかも成果が数字で出るため、費用対効果に見合わなくても着手されやすいという性質があります。面白さと重要さを分けて考える必要があります。
3. 早すぎる最適化
は、測る前に、遅いと思い込んだ箇所を作り込んでしまうことです。害は2つあります。
- 可読性を損なう — 読みにくいコードが残るが、速くなっていない
- 実際の は別の場所にある — 労力が無駄になる
この連載で繰り返してきた「計測してから手を付ける」は、まさにこれを避けるための順序です。推測が当たる確率は思っているより低い。特に、待ちが支配的な業務システムでは、計算量の直感はほとんど当たりません。
この言葉は最適化を否定するものではありません。否定されているのは「早すぎる」ほう、つまり根拠を持たずに始めることです。測って根拠があるなら、作り込むこと自体は正当です。
4. ただし、後から直せないものは先に決める
「測ってから」が原則ですが、例外があります。後から変えるのが極端に難しいものは、最初に決める必要があります。
| 項目 | 後から変えられるか | 対応 |
|---|---|---|
| 処理の書き方 | 容易 | 測ってから直せばよい |
| 索引の構成 | 容易 | 後から追加・削除できる |
| キャッシュの導入 | 比較的容易 | 後から入れられる |
| データの持ち方・分割 | 難しい | 最初に検討する |
| 同期か非同期か | 難しい | 最初に検討する |
| 件数の上限の有無 | 難しい | 最初に入れる |
下の3つは、後から変えると影響範囲が広くなります。特に件数の上限は、この連載で繰り返し出てきました。N+1(EP.5)でも、メモリ(EP.9)でも、根っこは同じです。上限は最初に入れるべき制約で、後から入れると既存の利用者に影響します。
逆に言えば、上の3つ ── 処理の書き方、 の構成、 の導入 ── は後から変えられるので、先回りして作り込む必要がありません。ここを最初から最適化しようとするのが、次に扱う「早すぎる最適化」の典型的な形です。後戻りのしやすさで、いま決めるべきかを判断するという基準は、性能以外の設計判断にもそのまま使えます。
5. 速くする代わりに、減らす・遅らせる
改善の選択肢は「速くする」だけではありません。そもそもやらない、後でやるという手があります。
- やめる — 誰も見ていない出力、使われていない機能(EP.7)
- 減らす — 件数の上限、取得する項目を絞る(EP.3)
- 後でやる — 同期でやっていた処理を非同期に回す
- 先にやっておく — 事前に集計しておき、参照時は読むだけにする
- 待たせ方を変える — 速くせず、体感だけ改善する(EP.8)
3番目の「後でやる」は効果が大きい選択です。利用者が結果を待つ必要がない処理なら、受け付けだけ返して裏で処理すればよい。応答時間は劇的に改善します。ただし失敗したときにどう伝えるかという設計が必要になり、これが本体の難しさです。
5番目は EP.8 で扱ったとおりで、1ミリ秒も速くせずに体感を改善できる場合があります。費用対効果でいえば、しばしば最良の選択です。
6. 判断を記録する
やらないと決めたことも記録します。記録がないと、半年後に同じ議論が起き、今度は誰かが「速くしよう」と動き出します。
- 1現在値と目標値 — 満たしているという事実
- 2やらないと判断した理由 — 何を優先したか
- 3やるとしたら何が必要か — 工数と、失うもの
- 4再検討する条件 — 「件数が10倍になったら」など
4番目が特に有効です。再検討の条件を書いておくと、判断が「永久にやらない」ではなく「いまはやらない」になります。条件が満たされたときに動けるので、先送りではなく判断として機能します。
速くすることは技術の問題だが、速くするかどうかは技術の問題ではない。
性能改善は必ず何かとの交換。特にキャッシュは正しさの保証を部分的に諦める判断になる。目標を満たしているなら、やらないのが原則。ただし後から変えにくいもの(データの持ち方、同期か非同期か、件数の上限)は最初に決める。そしてやらない判断も、再検討の条件つきで記録する。
この記事の感想を教えてください
あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。