ハクソク

世界を動かす技術を、日本語で。

ロブ・パイクのプログラミングに関する5つのルール

概要

  • プログラムのボトルネックは予想外の場所に現れる点
  • 最適化は計測後に行うべきという原則
  • 複雑なアルゴリズムは小規模データには向かないこと
  • シンプルなアルゴリズムとデータ構造の重要性
  • データ構造選択がプログラミングの中心である点

プログラム最適化に関するPikeのルール

  • ルール1:プログラムのどこで時間がかかるかは予測困難
    ボトルネックは意外な場所に現れがち
    速度向上の工夫は、実際に問題箇所を特定してから実施

  • ルール2:必ず計測してから最適化
    速度向上のための調整は、計測データに基づき実施
    一部のコードが全体を圧倒する場合のみ最適化を検討

  • ルール3複雑なアルゴリズムは小さいnでは遅い
    nが小さい場合はシンプルな方法が有効
    大きなnの場合でも、まず計測(ルール2)を優先

  • ルール4複雑なアルゴリズムはバグが多く実装も難解
    シンプルなアルゴリズムシンプルなデータ構造を推奨

  • ルール5データ構造が最重要
    適切なデータ構造選択と整理でアルゴリズムも自明となる
    プログラミングの中心はアルゴリズムでなくデータ構造

関連する有名な格言・設計哲学

  • ルール1・2はTony Hoareの「Premature optimization is the root of all evil(早すぎる最適化は諸悪の根源)」の再表現
  • ルール3・4はKen Thompsonによる「When in doubt, use brute force.(迷ったら力技でやれ)」に該当
    • KISS原則(Keep It Simple, Stupid)の具体例
  • ルール5はFred Brooksの「The Mythical Man-Month」で言及
    • write stupid code that uses smart objects(賢いオブジェクトを使った単純なコードを書け)」と要約されることも多い

まとめ

  • 最適化は計測と根拠に基づく判断が重要
  • シンプルさデータ構造重視の設計思想
  • 歴史的な名言や原則に裏打ちされたプログラミングのベストプラクティス

Hackerたちの意見

アラン・J・パーリスの「プログラミングのエピグラム」には、短い知恵の断片がたくさんあるよ :) https://www.cs.yale.edu/homes/perlis-alan/quotes.html > ルール5. データが支配する。正しいデータ構造を選んで、うまく整理できていれば、アルゴリズムはほとんど自明だよ。プログラミングの中心はアルゴリズムじゃなくてデータ構造なんだ。パーリスのバージョンが好きだったな。ちょっとファンクショナルプログラミングで使いすぎかもしれないけど、ニュアンスを考えれば実際にはうまくいくことが多いよね。 > 9. 10個のデータ構造に10個の関数を使うより、1つのデータ構造に100個の関数を使う方がいい。
実際の引用はこうだと思うよ: 「フローチャートを見せて、テーブルを隠せば、私はずっと混乱するだろう。テーブルを見せてくれれば、フローチャートは必要ない。明らかだから。」 -- フレッド・ブルックス、『神話のマン・マンス』(1975年)
さらにこういうのもあるよ: > 実際、悪いプログラマーと良いプログラマーの違いは、コードとデータ構造のどちらを重要視するかだと主張するよ。悪いプログラマーはコードを気にする。良いプログラマーはデータ構造とその関係を気にする。 -- リーナス・トーバルズ
HaskellやReScript/OCamlみたいな言語はCRUDアプリケーションにすごく合ってると思う。データと型についてまず考えさせられるから。その後、関数を通じてデータに対してどんな変換をしたいかを考える。新しいコードを見るときは、まず型を確認することが多い。具体的には、何が保存されていて、何が読み込まれているかをね。
ペルリスがたまに言及されるのを見るのは嬉しいね。SICPを再読してるけど、まだ新しいことを学んでるよ。
アラン・ケイとリッチ・ヒッキーのスレッドを思い出した。アラン・ケイは「データ」は悪いアイデアだと思ってる。彼の視点の解釈としては、必要なのはデータを「説明する」プロセスやインタープリター、ライブオブジェクトだってことだ。https://news.ycombinator.com/item?id=11945722 編集: 彼はQuoraでもっと詳しく書いてるよ。要するに、プログラミングの中心は「データ」じゃなくて「意味」だと言ってる。https://qr.ae/pCVB9m
100個の機能と1つのデータ構造があれば、グローバル変数でプログラミングしてるのとほぼ同じだよね。新しいインスタンスが新しいプロセスに相当する感じ。これ、あんまり良いルールじゃない気がする。
大学卒業したての頃に読んだ「Dive into Python」のこの引用は、プログラミングの本で読んだ中で一番影響を受けた言葉の一つだな。 > 「忙しい作業のコードは重要じゃない。データが重要だ。そしてデータは難しくない。ただのデータだ。もしデータが多すぎるなら、フィルターをかければいい。欲しいものでなければ、マッピングすればいい。データに集中して、忙しい作業は置いておけ。」
基本的に逆のことを言ってるんじゃない?パーリスは「正しいデータ構造を選ばず、人気のあるものにデータを押し込めろ」って言ってる。これは汎用プログラミングが広まる前は意味があったかもしれないけど、今は時代遅れだと思う。
> ルール5. データが支配する。正しいデータ構造を選んで、物事をうまく整理できていれば、アルゴリズムはほぼ自明だ。プログラミングの中心はアルゴリズムではなくデータ構造だ。30〜40年コードを書いてきて学んだことはこれだ。
でも、2番目のルールはパイクの5番目のルールと直接対立してるんじゃない?これらはすべて、塩をひとつまみ加えて考えるべき格言のように思える。 > 2. 関数はバインディングを遅らせる; データ構造はバインディングを引き起こす。道徳: プログラミングプロセスの後半でデータを構造化すること。
1と2は新しさがある場合にしか当てはまらない気がする。というのも、同じようなシステムを同じドメインでたくさん作ると、どこを最適化すべきかなんとなくわかるから。ほとんどの人は同じようなシステムを作る傾向があって、特定のドメインでキャリアの大部分を過ごすことが多いよね。経験と直感だけでパフォーマンスのボトルネックがどこになるかを事前に見抜けないなら、スタッフやプリンシパルとは言えない気がする。
毎回、あるエリアが主要なボトルネックになると予想していたら、実際にそうなっている気がする。時々、期待よりもパフォーマンスが悪いエリアもあるけど、たいていはコードがうまく書けてない部分だね。でも、計算負荷が高いエリアやリモートコールが多いエリアは、プログラムする前に簡単に見つけられるよ。プロジェクトを始める前にパフォーマンステストを何度かやって、十分に速くできるか確認している。全体のアプローチは、何かがどれだけ早くできるかによって変わることが多いよ。
ロブ・パイクはUnixとGolangを書いたけど、確かに君は特別だね。
笑った、パイクが何を言ってるのか分かってたらいいのに。/s ;)
> どこを最適化すべきかはなんとなくわかるよね。 ルールは「なんとなく」破られるためにある。自由でいよう。俺はプログラミングできる限り、このルールを守ってきたし(もう30年やってる)、これからも守るつもり。個人的には、ボトルネックが起こりそうだって感じることはできるけど、どこで、いつ、どうなるかは絶対にわからないよ。
> ルール5は「賢いオブジェクトを使った愚かなコードを書く」と短縮されることが多いけど、これは「短縮」という言葉の最悪の使い方だと思う。もっと「 mutilated(切り刻まれた)」の方が合ってるんじゃない?
構文糖はセミコロンの癌だね。
ルール5は間違いなく重要だね。コードはデータに作用するから、データがクソだったらもう終わり。編集: s/data/data structure/
… データ構造がクソだったら。良いソフトウェアはクソデータを扱えるよ。
ホーアへの帰属はよくある間違いだね。「早すぎる最適化はすべての悪の根源」という言葉は、クヌースの1974年の論文「構造化プログラミングにおけるgoto文」で初めて登場した。クヌースは後にこれをホーアに帰属させたけど、ホーアは覚えていないと言って、ダイクストラの可能性を示唆した。ルール5は一番良く残った。「データが支配する」というのは、すべてのシニアエンジニアが最終的に辛い目に遭って学ぶ教訓だね。
ずっとダイクストラの言葉だと思ってた。なんかダイクストラっぽい響きだし。
前の議論: https://news.ycombinator.com/item?id=15776124 (8年前、コメント18件)
ソフトウェア開発のプロジェクトにこれほどダメージを与えたフレーズは歴史上ほとんどないと思う。「早すぎる最適化はすべての悪の根源だ。」まず、トニー・ホーアの名誉を傷つけるのはやめよう。この引用はドナルド・クヌースからのもので、欠けている文脈が重要なんだ。彼の1974年の論文「GOTO文を用いた構造化プログラミング」からの引用: 「プログラマーは、プログラムの非クリティカルな部分の速度について考えたり心配したりするのに膨大な時間を浪費していて、これらの効率化の試みは実際にはデバッグやメンテナンスを考慮すると強い悪影響を及ぼす。小さな効率性については97%の時間を忘れるべきだ。早すぎる最適化はすべての悪の根源だ。しかし、そのクリティカルな3%の機会を逃してはいけない。」彼はC言語のGOTO文の使用について話していたんだ。マイクロ最適化の名のもとにソフトウェアを理解しづらくすることについて話していた。彼は(間違って)私たちがソフトウェアが動く機械を尊重するだろうと考えていた。今や何世代ものプログラマーが、無駄に非効率で膨れ上がった遅いソフトウェアが全然問題ないと信じるようになってしまった。コンピュータが実行するボイラープレートや間接的な処理に限界はない。これらの天才から生まれる結晶のような抽象化に上限はない。JVMが起動するのにかかる時間に長すぎるということはない。昔、Googleで働いてたけど、この引用の意図を誤解したことから生まれる悪夢を実際に体験したよ。もう結構だ。二度とごめんだ。これらの罪を他のどれよりも多く犯してきたし、それに対して怒りが収まらない。
> そして、欠けているコンテキストは重要だ。そうだね、このフレーズを使う人には、残りの論文を読んで、クヌースが正当だと考える最適化の種類を見てほしい。例えば、クイックソートでのメモリアクセスの最適化とか。
完全に同意だね。この文脈から外れると、「早すぎる」という言葉は色々な意味を持ちすぎるよ。
正直に言うと、これはあまり乱用されていない引用の一つで、僕はこれから得られる利益の方が害よりも多いと思ってる。君と同じように、遅いコードをたくさん書く人を見てきたけど、ほとんどは速いコードを書くのが本当に難しい人たちだよ。遅いソフトウェアは嫌いだけど、インチキなソフトウェアよりはマシだと思う。一般的に、パフォーマンスの問題を修正する方が、間違った動作を修正するよりも簡単だし、特にそのエラーがアクセスできないどこかに保存されたデータを生み出してしまった場合はね。でも、もっと言うと、その害が現実世界に及んでしまったときはさらに厄介だよ。
> 複数世代のプログラマーが、無駄に非効率で膨れ上がった遅いソフトウェアが全然問題ないと信じるように育ってしまった。コンピュータが実行するボイラープレートや間接呼び出しの量に限界はない。これらの天才から生まれる結晶のような抽象化には上限がない。JVMが起動するのにかかる時間に制限はない。これは早すぎる最適化をする人たちのせいだと思う!もし人々がこの引用を真剣に受け止めていたら、ボイラープレートや間接呼び出しの量を増やすことにはあまり傾かないはずだ。
わかるよ、友よ!君がグーグルでJavaの問題を見ている間、僕はPythonでそれを見ていた。無駄な間接呼び出しが多すぎる。まじで!必要のないスーパークラスやミックスインがたくさん!人間の理解を超える深さの間接呼び出しがあると、コードを理解するのが難しくなるよ。リスト内包表記が魔法のように良いと信じられていて、ネストしたforループの方が読みやすくて速いのに、リスト内包表記がフェティッシュ化されてしまって、自然な読みやすさの限界を超えてしまった。結果として、君が今苦しんでいる長文を読むような感じになったよ。
プロファイルを見るまで最適化の機会を無視するのは、実際にプロファイルを取ったときだけうまくいく!プロファイリングは、コンパイルやリント、ユニットテストのように、ほとんどの開発者のコアループに入ることはなかった。どれだけのCI/CDパイプラインがテスト結果と一緒にフレームグラフを出力しているんだろう?
最初の4つはちょっと関連してるね。僕にとって5つ目が一番重要で、よく見落とされがちなポイントだと思う。> データが支配する。正しいデータ構造を選んで、うまく整理できていれば、アルゴリズムはほぼ自明になるよ。プログラミングの中心はアルゴリズムじゃなくてデータ構造なんだ。
5については全く同意だよ。本当に難しいプログラミングの問題は、データ構造の反復的な改良(それに関連するAPIも含めて)によって(最終的に)解決されることが多いって感じてる。うまくいくと、プログラムの制御フローは直感的に理解しやすくなるよ。お気に入りの話題に戻るけど、僕はコーディングタスクのサポートにLLMをよく使うけど、これに関してはあまり得意じゃないと思う。クロードは小さなデータ型に対して複雑な制御フローのロジックを提案したり拡張したりすることは得意だけど、アイデアをコンポーザブルなチャンクにカプセル化する機会を認識して実装するのは苦手だと思う。今のところ、ほとんどのコードがLLMによって生成・消費されるから関係ないって考えは納得できないな。今のLLMは、すでに考え抜かれた設計のコードベースに対してはずっと効果的だし、人間もそうだよ。なんでそれが変わると思う?