コンテンツにスキップ

判断ガイド: 最適化すべきか・リファクタリングすべきか

どちらも「機能が増えない作業」への投資判断です。共通原則: 痛みの証拠(計測・履歴)を要求し、投資対効果で決める

最適化すべきか

Q1. 性能目標(フレーム時間・メモリ・ロード時間)を数字で言えるか?
    → 言えない ──> まず目標設定(目標なき最適化は終わらない)
Q2. 目標を満たしていないか?(実機・Shipping相当構成で計測 → [ビルド構成](../08_build_system/04_build_configurations.md))
    → 満たしている ──> 最適化しない(浮いた時間で機能・品質へ)
Q3. プロファイラでボトルネックを特定したか?
    → していない ──> 計測が先。「たぶんここが遅い」は大抵外れる
Q4. ボトルネックへの対策を、コスト順に検討:
    (1) 無駄の削除(呼ばなくていい処理、空Update、重複計算)← まずここ。設計を汚さない
    (2) アルゴリズム・データ構造(O(N²)→[空間分割](../04_game_patterns/optimization_patterns.md)、[キャッシュ局所性](../07_memory_and_runtime/05_cache_locality_aos_soa.md))
    (3) 構造の変更(プール、SoA、並列化)← 可読性を払う。効果を再計測で確認
    (4) 低レベル(SIMD手書き、アセンブリ確認)← 最後の手段
Q5. 例外 — 最初から設計に織り込むもの:
    データレイアウト・フレーム構造・アセットストリーミングなど「後から変えられない」性能決定
    ([早すぎる最適化](../01_design_basics/09_yagni_kiss_dry.md)の「例外」節)
  • トレードオフ: 速度 ⇔ 可読性・移植性・開発速度。「最適化した状態」は保守コストが高いので、目標を満たしたら止める
  • 罠: デバッグビルドで計測(最適化なしの計測は無意味)/計測コードが最適化で消える/平均だけ見てスパイク(GC・ロード)を見逃す

リファクタリングすべきか

Q1. そのコードを近々(今スプリント〜数週間)変更する予定があるか?
    → ない ──> しない(触らないコードの負債は利息ゼロ → [技術的負債](../01_design_basics/10_tech_debt_and_refactoring.md))
    → ある ──> Q2へ
Q2. 現在の構造が、その変更を高くしているか?(見積りの差で考える:
    「今の構造で2日、直せば半日+リファクタ1日」なら、2回目の変更から黒字)
    → 高くしていない ──> しない(綺麗さのためのリファクタは投資でなく趣味)
    → 高くしている ──> Q3へ
Q3. 振る舞いを固定する手段(テスト、確認手順)はあるか?
    → ない ──> 先に作る(なしでのリファクタは改悪リスクが利益を食う)
Q4. 実行: 機能追加と混ぜず、小さく、動かしたまま
    (準備のリファクタ → 機能追加 → 掃除のリファクタ、を別コミットで)
  • 最良のタイミングは「これから触る場所を、触るついでに」(準備のリファクタリング)。専用の「リファクタリング週間」より、日々の変更に混ぜる方が安全で確実
  • リリース直前・振る舞い固定手段なし・触る予定なし、の3条件はどれか1つでも「今はしない」

2つの判断の関係

  • 最適化とリファクタリングは逆方向の変形になりがち(最適化は構造を特殊化し、リファクタリングは一般化する)。同時にやらない
  • ただし「変更しやすい構造」は最適化の前提でもある(ボトルネックを差し替えられる構造 → 品質特性の衝突)——順序は「リファクタで変更可能に → 計測 → 局所を最適化」

理解度チェック

  1. 最適化の前に必要な2つのもの(目標・計測)がない場合、何が起きますか。
  2. 「触らないコードの負債は利息ゼロ」の意味と、その帰結は?
  3. 最適化とリファクタリングを同時にやるべきでない理由は?

前: C++の選択 | カテゴリ目次 | 次: 演習