概要
- if文 は呼び出し元に「上げる」ことで、制御フローを明確化することが推奨される提案。
- for文 は「下げる」ことで、バッチ処理やパフォーマンス向上を図る設計指針。
- 制御フローの集中管理 により、冗長性やデッドコードの発見が容易になることを強調。
- バッチ処理の導入 は、パフォーマンスや表現力の両面でメリットがあることを説明。
- ifとforの最適な配置により、可読性・効率性の高い設計を目指すことを推奨。
if文は上に、for文は下に ― 制御フロー設計の指針
if文を「上に」押し上げる理由
- 関数内部の if条件 は、可能であれば 呼び出し元に移動 することを推奨。
- 前提条件(precondition) のチェックは、関数内で「何もしない」よりも、呼び出し側でチェック・型やassertで保証することが望ましい確認。
- 前提条件のチェックを「上げる」ことで、 全体のチェック回数が減り、冗長な分岐が減少 する提案。
- 制御フローやif文は複雑化・バグの温床 となりやすいため、1箇所に集約することで 全体像の把握やデッドコードの発見 が容易になる確認。
- 例:
-
一つの関数で複雑な分岐を管理し、 処理本体は単純なサブルーチンに委譲 することを推奨。
-
分岐が各所に分散すると、 冗長性や死んだ分岐が見落とされやすい ことを指摘。
-
enumの「溶解」リファクタリング
- 条件分岐がenumやmatchとして繰り返される場合、 分岐を上に集約することで重複や無駄を排除 することが可能。
-
for文を「下に」押し下げる理由
- データ指向設計 の観点から、 多くのオブジェクトを一括で処理するバッチ処理 を推奨。
- バッチ処理関数 を基本とし、スカラー(個別)処理は特殊ケースとして扱うことを提案。
- 例:
- GOOD:
frobnicate_batch(walruses) - BAD:
for walrus in walruses { frobnicate(walrus) }
- GOOD:
- 例:
- パフォーマンス向上 が主な動機であり、バッチ処理により 初期化コストの分散や処理順序の柔軟化 が可能となる確認。
- ベクトル化や構造体配列化 など、高度な最適化も実現可能な設計。
- FFTによる多点評価 のように、 一括処理が個別処理の繰り返しより高速 になるケースも存在する指摘。
- 表現力の向上 にも寄与し、jQueryのような「コレクション指向」なAPI設計も例示。
ifとforの組み合わせパターン
- if文をfor文の外側に配置 することで、条件評価の重複を避け、 ホットループ内の分岐を削減・ベクトル化を促進 することが可能。
- GOOD:
if condition { for walrus in walruses { walrus.frobnicate() } } else { for walrus in walruses { walrus.transmogrify() } } - BAD:
for walrus in walruses { if condition { walrus.frobnicate() } else { walrus.transmogrify() } }
- GOOD:
- TigerBeetleの設計 のように、 データプレーンでバッチ処理を徹底 し、制御プレーンの意思決定コストを分散するアーキテクチャも紹介。
まとめ
- if文は「上」に、for文は「下」に 配置することで、 制御フローの明確化・パフォーマンス向上・表現力強化 を実現することを推奨。
- 設計・リファクタリング時にこの指針を意識 することが、バグの削減やメンテナンス性向上に寄与する提案。