36 ポイント 投稿者 GN⁺ 2026-03-19 | 1件のコメント | WhatsAppで共有
  • ルール 1: プログラムがどこで時間を消費するかは予測できない。ボトルネックは予想外の場所で発生するため、実際にボトルネックであることが証明されるまで高速化を試みてはならない
  • ルール 2: 計測が先。速度調整は計測後にのみ行い、コードの一部が全体を圧倒しているときにだけ最適化を検討する
  • ルール 3: 複雑なアルゴリズムは小さな n では遅い。複雑なアルゴリズムは大きな定数を持つため、n が頻繁に大きくならない限り単純な方法を使うべき。n が大きくなる場合でも、まずルール 2 を適用しなければならない
  • ルール 4: 複雑なアルゴリズムはバグが多く、実装が難しい。単純なアルゴリズムと単純なデータ構造を使うことが望ましい
  • ルール 5: データが核心。正しいデータ構造を選び、うまく整理すれば、アルゴリズムはほとんど自明に見えてくる。プログラミングの中心はアルゴリズムではなくデータ構造である

関連する哲学と引用

  • ルール 1 と 2 は、Tony Hoare の 「早すぎる最適化は諸悪の根源」 という格言と同じ意味
  • Ken Thompson はルール 3 と 4 を 「疑わしいときは単純な方法(Brute Force)を使え」 と再解釈した
  • ルール 3 と 4 は KISS(Keep It Simple, Stupid) 設計哲学の例
  • ルール 5 は Fred Brooks が『The Mythical Man-Month』ですでに述べていた内容で、
    しばしば 「賢いオブジェクトを使って単純なコードを書く」 と要約される

1件のコメント

 
GN⁺ 2026-03-19
Hacker Newsのコメント
  • Jonathan Blowの講演を思い出した
    彼は生産性の観点からアプローチしていた。Braid開発初期にはほぼすべてを単純な配列で実装し、ボトルネックが発生したときだけ修正していた
    「速度やメモリよりも重要なのは、1つのプログラムを実装するのにかかる人生の時間だ」という言葉が印象的だった

    • ゲームは多数の類似オブジェクトを毎秒60フレーム以上で繰り返し処理するので、単純な配列ベースの構造が合理的なデフォルトになる
    • ゲーム開発では16ms以内にフレームをレンダリングしなければならないため、固定サイズのテーブルと線形探索がよくあるパターンだ。動的割り当ての予測不可能性を避けるための構造的選択でもある
    • この観点はゲーム以外の一般的な開発にも通じる。私たちは皆、締め切りとコスト制約の中で働いているので、エンジニアリング時間そのものがコストだ
    • ただしゲームの教訓を一般プログラミングにそのまま拡張するのは慎重であるべきだ。ゲームは再利用より特定用途のコードが中心で、一般ソフトウェアはデータ中心だからだ
    • 私の場合は配列ではなくハッシュマップから始めるタイプだ
  • Rule 1を本気で受け入れるなら、Rule 3〜5は自然についてくる
    ボトルネックは予測できないという前提を認めるなら、単純なコードを書いて測定することが唯一の合理的な戦略になる
    実際によく失敗するのは早すぎる最適化ではなく、早すぎる抽象化だ。不要な柔軟性のために複雑な階層を作り、それがかえって保守コストを押し上げる

    • 「抽象化は自然に現れるべきであって、先に設計するものではない」という言葉をチーム内でよく引用している
    • 早すぎる抽象化は開発者の時間を浪費し、技術的負債を増やし、バグの可能性を高める。しばしば「将来の問題に備える」という名目で生まれる
    • 関連論文としてPhilip Wadlerの文章は参考になる
    • 私は性能より可読性と保守性を重視する。だから私にとってはRule 4が根本で、Rule 1はその結果だ
    • 複雑な設定ファイルを過度に分割した事例を経験したが、結局は単純なYAMLファイル8個で十分だった
  • 90年代に深夜2時、データセット検索機能を実装しなければならなかったことがある
    疲れていたのでひとまず線形探索で実装して後で直そうと思ったが、実際には4時間のテストで6秒しか差が出なかった
    結局修正はしたものの、意味のある差はなかった

    • nが小さいなら、むしろ線形探索のほうが速いこともある
    • ただしO(n²)アルゴリズムには、「リリースはできても、最終的には本番で爆発する」危険がある
  • Rule 5には全面的に共感する
    難しい問題ほどデータ構造とAPIの反復的改善によって解決される。構造がうまく定まれば、制御フローは自然になる
    LLMはこうした構造的思考が苦手だ。複雑な制御フローはうまく提案するが、組み合わせ可能なデータ構造の設計は得意ではない

    • 私の経験ではRule 5こそ事実上のRule 1だ。「コードを見せられると混乱するが、データベーススキーマを見せられるとすべてが明確になる」という言い方がある
    • 分散サービスではRule 5がしばしば無視される。複数のHTTP・DB呼び出しに分けるより、1回の呼び出しで処理できる構造のほうが効率的だ
  • 私は電子工学(E.E.)出身で、Rule 3のおかげでキャリア初期には大きな問題はなかった
    しかし後に大規模システムへ移るとnが大きくなり、計算量が本当に重要になった
    Rob Pikeが話していた時代の「ビッグアイアン」は、今でいう組み込み環境に近かった

    • 私はRule 3に一部反対だ。入力が小さいなら問題ないが、大きい入力ではBig-O性能が重要になる。
      2つのアルゴリズムで実装難易度が同じくらいなら、大きな入力で速いほうを選ぶ
      関連記事: Less Than Quadratic
    • 「fancy」の意味は問題領域に合わせて解釈すべきだ。nが小さいなら単純なアプローチのほうがよいが、nが大きいなら高度なアルゴリズムが必須になる
      人はしばしば単純すぎるO(n²)アプローチを選び、本番で爆発するのを経験する
    • 父はFortran時代からlookup tableを好んで使っていた。繰り返し計算を減らす古典的な最適化手法だ
  • Pikeのルールは、従来の格言より優れていると思う
    「早すぎる最適化は諸悪の根源」といった文は文脈が失われると誤解されやすい
    Pikeのバージョンは明確で、誤用されにくい
    「Rule 5は『賢いオブジェクトを使わせて、コードは愚かにしておけ』と要約できる」という昔の言い方があったが、
    オブジェクト指向の時代にはむしろ複雑さを隠す誤った信念へと変質してしまった

    • 歴史的な思考のつながりを保つことは重要だ
    • 「古典的格言の精神的クリックベイト」という表現は、ちょっとした気の利いた比喩に感じられる
  • 10年以上同じコードベースを運用してきて、Pikeのルールを完全に体得した
    KISS/DRY原則を守り、流行の技術より実績のある技術を維持することが、長期的には安定につながった
    実際、私たちのチームの開発原則文書はPikeのルールとほぼ同じ内容だ

  • 1990年代初頭のC++時代、双方向連結リストの代わりに単純な配列の再割り当てに変えたところ、
    バグが消えただけでなく、むしろ速くなった。
    高価な操作をより少ない頻度で行うことがよい戦略だと学んだ

  • 「測定せずにチューニングするな」というルールと、Jeff DeanのLatency Numbers Every Programmer Should Knowを比べると興味深い
    Deanは事前知識によって性能を予測できると述べている
    結局、この2つの立場は両立できる。設計段階では感覚的に速そうな構造を選び、実装後には測定ベースで微調整すべきだ

    • 本当に速いコードは両方のアプローチを使う。設計段階でキャッシュ効率を考え、その後プロファイリングでボトルネックを除去する
    • レイテンシーの数値はアルゴリズムの理論的な限界線を示すだけで、実際の性能は実装や実行環境によって変わる
    • 「早すぎる最適化」が禁じているのは、局所的なハックレベルのチューニングだ。全体設計で速度を考慮するのは当然だ
  • Rule 1と2が絶対なのは、新しい問題を扱うときだけだ
    同じドメインで繰り返しシステムを作っていると、ボトルネック箇所を事前に予測できるようになる
    経験豊富な開発者なら、設計前からおおよその性能感を持てる

    • 私もほとんどの場合、ボトルネックを正確に予測できた。事前の性能テストでアプローチを変えたことも多い
    • ただし30年の経験から言うと、ボトルネックが起きそうだという勘は当たっても、正確な位置や時点は予測できない
    • 「Rob Pikeに何がわかるんだ」という冗談もあったが、彼はUnixとGoを作った人物だ。彼のルールには理由がある