1 ポイント 投稿者 GN⁺ 2023-11-16 | 1件のコメント | WhatsAppで共有

関数内の条件分岐を上へ移動

  • 関数内に if 条件分岐があるなら、それを呼び出し側(caller)へ移すことを検討する。
  • 関数が前提条件を内部で確認し、条件を満たさないときに「何もしない」のではなく、呼び出し側が前提条件を確認することで、型によって前提条件が満たされていることを保証する。
  • 前提条件をとくに「上へ移動」すると、全体として確認作業を減らせることがあり、これがこのルールの動機の一つである。

ループを下へ移動

  • データ指向の発想から生まれたルールで、オブジェクトの「バッチ(batch)」という概念を導入し、バッチ処理を基本ケースとし、スカラ版をバッチ版の特殊ケースとして扱う。
  • 主な利点は性能向上であり、開始コストを分散でき、処理順序にも柔軟性を持たせられる。
  • たとえば、FFT ベースの多項式乗算では、複数の点で同時に多項式を評価するほうが、個別に評価するより速いことがある。

GN⁺の意見

  • この記事で最も重要なのは、ソフトウェア開発で性能とコードの明快さを高めるための 2 つのプログラミング規則、「条件分岐を上へ移動」と「ループを下へ移動」である。
  • これらの規則は、コードの可読性を高め、性能を最適化し、バグの発生可能性を減らすのに役立つ。
  • ソフトウェアエンジニアリングの複雑さを管理し、効率的なコードを書く方法への洞察を与えるため、この記事は多くの開発者にとって興味深く有益である。

1件のコメント

 
GN⁺ 2023-11-16
Hacker Newsの意見
  • データ指向設計に関する助言への反発が驚きだという意見がある。フォーラム利用者の大半はWebアプリケーションを書いているため、この助言は無意味に見えるかもしれない。日常業務で命令キャッシュについて考える必要がないなら、この助言は無視すべきだ。Mike Actonの"Typical C++ Bullshit"を見れば、この助言の重要性を理解できる。
  • プログラマーはコードを「小さな単位」で美しく作ることには気を配る一方で、コードベース全体の適切な設計には十分に注意を払っていないという意見がある。関数の名前が適切で、良いインターフェースを持ち、目的が明確で、適切に文書化されており、副作用を過度に使っていないなら、関数の中身が多少雑でも、iffor の配置についてはそれほど気にしなくてよい。
  • 科学分野でプログラミングを始めた人からは、小さな最適化が重要だという意見がある。for ループの順序を誤るだけで、シミュレーションの実行時間が1週間から1時間に短縮されることがある。このような背景を持つ人は、forif の順序を本能的に最適化する。
  • 「コンテナ」がある場合、コンテナに対する関数を書くのではなく、コンテナが保持するドメインレベルの「Thing」に対する関数を書くべきだという意見がある。これによりコードの柔軟性が高まり、中核ドメインとアプリケーションの関心事をより明確に分離できる。
  • 関数の事前条件と事後条件が、if を上に移動させることで関数定義から直接見えなくなるという欠点がある。大規模プロジェクトでは、このような関数が意図した文脈の外で再利用され、バグを引き起こす可能性がある。契約フレームワークを使うのも一つの解決策だが、契約とコードの両方に条件を二重に書かなければならない。
  • Rustを使った例では、Rustの強力な型システムが、他の言語で必要になりがちな防御的プログラミングを不要にしている。Cプログラマーが関数に渡されたポインタの妥当性を確認せずにNULL参照を起こすのは望ましくない。いくつかの if は関数の末尾ではなく先頭に置かれるべきであり、エラーは適切に伝播されるべきだ。
  • 記事は特定のコード例につながるように見えたが、実際にはそうではなかったという意見がある。期待していたコード例の代わりに、別の例を示している。
  • 適切な文脈がなければ、この助言は奇妙で、場合によっては悪い助言にすらなり得る。for ループと if 文はどちらも制御フロー演算であり、記事の一部の主張は意味をなしていないように見える。性能に関する主張が最も強いが、一般的な助言としては最後に考慮すべき懸念事項だ。
  • 一般的なルールが実際のコードに適用できるか確信できないという意見がある。こうしたルールはしばしば誤ったドグマと見なされ、若いプログラマーがそれを誤って受け取り、より悪いコードを書いてしまうおそれがある。条件が walrus に依存することが多いため、if を上に移動できない。
  • 事前条件の if を呼び出し側に移すのはひどいアイデアだという意見がある。特殊な場合には良い考えかもしれないが、一般的には望ましくない。ライブラリでは外部境界で事前条件を確認し、内部実装が内部の仮定なしに進められるようにすべきだ。呼び出し側の確認に依存すると、その目的が失われる。