If を上へ、For を下へ移す
(matklad.github.io)- 関数内部の if 文を呼び出し側へ引き上げると、コードの 複雑さの軽減に役立つ
- 条件チェックと分岐処理を一か所に集約すると、重複や不要な分岐確認を見つけやすくなる
- enum 分解リファクタリングを使うことで、同じ条件がコードのあちこちに散らばる問題を防げる
- バッチ演算ベースの for 文は、性能向上と反復処理の最適化に効果的
- if は上へ、for は下へというパターンを組み合わせることで、コードの可読性と効率を同時に高められる
2つの関連ルールについての簡単なメモ
- 関数内に if 条件文がある場合、それを関数の呼び出し側へ移せないか考えるやり方が推奨される
- 例のように、関数内部で precondition(前提条件)を検査するより、呼び出し側にその条件チェックを任せるか、型(あるいは assert)によって前提条件を保証するようにするのが望ましい
- 前提条件の検査を上へ引き上げる(Push up)やり方はコード全体に影響し、全体として 不要な条件チェックの数を減らす効果をもたらす
制御フローと条件文の集約
- 制御フローと if 文は、コードの複雑さやバグの主な原因である
- 条件文を呼び出し側など上位に集約して、分岐処理を1つの関数に集中させ、実際の処理は直線的な(ストレートラインの)サブルーチンに任せるパターンが有益
- 分岐と制御フローが一か所に集まると、重複した分岐や 不要な条件を簡単に把握できる
例:
- f 関数内にネストした if があるときは、死んだコード(Dead Branch)を認識しやすい
- 複数の関数(g, h)を通じて分岐が分散すると、こうした把握が難しくなる
enum 分解リファクタリング(Dissolving enum Refactor)
- コードが同じ条件分岐を enum などに内包している場合、条件を上位へ引き上げることで、分岐と処理をより明確に分離できる
- この方法を適用すると、同じ条件がコード内で 何度も繰り返し現れる問題を防げる
例:
- 同じ分岐条件が f、g 関数と enum E にそれぞれ表現されている状況を
- 1つの上位条件分岐にまとめることで、コード全体を単純化できる
データ指向の考え方(Data Oriented Thinking)とバッチ演算
- ほとんどのプログラムは複数のオブジェクト(エンティティ)で動作する。クリティカルパス(Hot Path)は、多数のオブジェクト処理によって性能が決まる
- バッチ(batch)の概念を導入し、オブジェクト集合に対する演算を基本にして、単一オブジェクトへの演算は特殊ケースとして扱うのが望ましい
例:
-
frobnicate_batch(walruses)のように バッチ処理関数を基本に置き、 -
個別オブジェクトは for ループで処理する特殊ケースへ変換できる
-
この方法は性能最適化の観点で重要な役割を果たし、大量処理ではスタートアップコストを減らし、順序の柔軟性を高める
-
SIMD 演算(struct-of-array など)の活用も可能で、特定フィールドだけを一括処理してから全体の処理を進められる
実践的な事例と推奨パターン
- FFT ベースの多項式乗算のように、複数地点での同時演算を可能にして性能を最大化できる
- 条件文を上へ、反復文を下へ移すルールは並行して適用できる
例:
- 反復文の内部で同じ条件式を何度も検査するより、条件文を反復文の外へ出したほうが、ループ内の分岐が減り、最適化とベクトル化がしやすくなる
- このアプローチは TigerBeetle の設計など、大規模システムのデータプレーンでも高い効率を保証する
結論
- if 文(条件文)は **上位(呼び出し側、制御側)**へ、for 文(反復文)は **下位(演算部、データ処理部)**へ下ろすパターンを組み合わせることで、コードの 可読性、効率、性能をすべて向上できる
- 抽象ベクトル空間の視点で考えること(集合単位の演算)は、反復的な分岐処理より優れた問題解決の道具となる
- 要するに、if は上へ、for は下へ!
1件のコメント
Hacker News の意見