
2026/03/12 9:53
**理解の必要性について**
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
Andy Wingo は、現代のプログラミングは「既知でよく文書化されたコンポーネントから構築する」よりも、Gerald Sussman が「ソフトウェアの基礎科学」と呼ぶような外国ライブラリを深く理解することが必要だと主張しています。彼は MIT が 6.001 コースで Scheme を放棄した理由として、2000 年代初頭のエンジニアリングが複雑で文書化されていないコードを生み出し、1980 年代のより明確な低レベルコードと対照的だったという Sussman の観察を引用しています。Wingo は自身のキャリアを語ります:8 ビットマシン(VIC‑20、Apple II)でのプログラミング、QBASIC、QuickC、その後 Windows/インターネットツール;高校時代に QNX の早期作業で C ポインタとメモリ管理を学んだこと;Allegro 音声統合用に Mikmod/Mikalleg をラップする「Easymik」を構築し、オンラインで公開したこと;周辺機器サポートのための XML 設定可能な汎用ツールキットを作成し、それが複雑すぎてスキーマをハードコーディングせざるを得なかったこと;そして 5 年間にわたり木合併アルゴリズムの仕事に従事し、Polya の「How to Solve It」チェックリストを適用し、ランダム化テストを実施し、最終的にはアルゴリズムをゼロから再構築して完璧な動作を達成したこと。
彼はオープンソースライブラリが今日では開発者にソースコードの検査を可能にする一方で、Windows 95 時代のようにソースが入手できない暗黙的な環境とは対照的だと強調しています。Wingo は Android UI レイアウトバグのデバッグ例を挙げ、
requestLayout/forceLayout がドキュメントで示されているようにレイアウトをスケジュールするのではなく、単にフラグを設定していることを発見しました。全体的なテーマは、コード検査と実際の実験によって内部動作を理解することが、現代の信頼できるソフトウェア開発には不可欠であるという点です。
本文
私は最近Andy WingoのMastodon投稿を見ました。
コーディングエージェントやそのほかが流行っているこの時代、私はジェラルド・サスマンが「もう既知の部品からシステムを構築することはなくなった。代わりに外国ライブラリの機能について基礎科学を行うべきだ」と述べたコメントをよく思い出します。彼はその時点で正しかった、そして私は16年前と同じくらいそれが嫌いです。
返信を書き始めましたが、すぐに長編エッセイへ発展してしまいました。実際、私にはずっと書きたかった関連する考えがたくさんあるのです。
リンク先ブログから抜粋:
コスタンザはサスマンに、MITが導入プログラミングコース6.001でSchemeをやめた理由を尋ねました。これは宝物です。彼はその背景が1980年の工学と1990年代中頃・2000年のものでは同じではなかったと言いました。1980年、優れたプログラマは多くの時間を思考に費やし、その後自分が動作すると信じる余剰コードを書きました。コードは金属近くで実行され、Schemeさえも理解できました。まるで抵抗器のように、バンドを読んで電力定格・許容差・抵抗値・(V=IR) を知り、それがすべてでした。6.001はエンジニアに完全に理解できる小さな部品を取り込み、単純な手法でそれらを組み合わせて望むものを作る方法を教えるために設計されました。
しかし今のプログラミングはそうではありません、とサスマンは言います。今やあなたは誰が書いたか分からないソフトウェアのマニュアルが読めない、あるいは存在しないものと戯れます。ライブラリがどのように動作するかを知るために基礎科学を行わなければならず、さまざまな入力を試してコードがどう反応するか観察します。これは根本的に異なる仕事であり、別のコースが必要でした。
(一次資料としては、59:35から始まる同じ質問へのサスマンの回答動画があります。)
私はこの主張について奇妙な感情を抱きます。世界中が動かすソフトウェアスタックは漏れた抽象化で構成されていることは明らかに正しいですし、ドキュメントが大幅に不足していて実験がより明確な理解へとつながるケースも多いです。しかしその意味合いとしては、「私たちは上に積み重ねるコンポーネントを理解できない」というほぼ絶対的な主張であり、90年代にはこの作業方法が終わり、現在のプログラミングは「うまく動くまで何度も叩くだけ」であると示唆しています。これは私自身の経験とは完全に逆です。
私は1982年生まれで、読むことができるようになるとすぐにプログラミングを始めました。初期は何も理解しておらず、物事は思い描くより速く複雑になっていきました。VIC‑20やApple IIの8ビットコンピュータでBASICを書いていた頃は、命令を順序立てるだけで「物事が起こる」ことでした。BASICにコマンドが無ければ何もできません。アセンブリ言語は存在するものの、別世界でした。Apple IIの機械語モニタに落ちたとき、唯一できることはCtrl+Resetを狂ったように叩いて BASIC プロンプトに戻ろうとするだけでした。
その後286プロセッサを手に入れ、QBASIC の制限に抵抗しました。コマンドが増えたのでより多くのことができましたが、それでも十分ではありませんでした。Microsoft QuickC を入手し、QBASIC で得た経験がもっと強力な言語へ移行すると期待していました。しかしヘルプファイルにはグラフィックスコマンドが全く示されていないという失望に直面しました。
やっとBBS にアクセスでき、VGA がどのように機能するかを説明したプログラミングチュートリアルを見つけました。さらに、shareware BASIC コンパイラでそれらのアイデアを試すことができました。まだ何が起きているか完全には理解していませんでしたが、概念に名前を付け、画面にピクセルを表示することは可能になりました。実際、私はひどいペイントプログラムを書いてピクセルを生成し、「幅・高さ・ピクセル」という簡易的なインターフェースだけで済ませました。
486 とインターネットの登場により、以前苦労して理解したツールはすべて使えなくなりました。古いものは残っていたものの、新しい複雑さの層の下に埋もれたのです。私は完全に迷子になり、自分の蓄積された知識が何度も粉々になる経験をしました。「次に学ぶべき重要なこと」は手の届かないところにあると感じました。本や書籍を読み、DPMI について新聞グループで投稿される記事を読んだり、リアルモードと保護モード間の BIOS コールがどうなるかを知ろうとしても、画面にピクセルを表示する方法は全く見つからなかったのです。
これが90年代中頃、サスマンが 6.001 の授業をやめた時期とほぼ一致します。ブログ投稿のパラフレーズは少し曖昧ですが、ビデオでは彼が「エンジニアリングが根本的に変わっている」ことを明言しています。この年代の私はそれを理解するために闘う10代でした!
世界で私が求めていたのはただ単純に何かを叩いて動くまで試すことだけでした。理解は馬鹿げたものでした。問題領域や自分の選んだプラットフォームの混沌とした現実について考えたくありませんでした。私はコンピュータに「物事を起こしてほしい」だけだったのです。単純な表面を持つライブラリや言語が欲しかったので、問題を自分で解決しなくても済むようにしたかったのです。
その時代の個人的達成感を共有します。私は当時誇りに思っていました。今は誇らしくありませんが、その出来事を思い出すことで、自分が本当にどんな状況だったかを覚えておけます。
DJGPP と Allegro によって、ゲーム作成のための「物事を起こす」コマンドの世界に戻ることができました。私は Scream Tracker で音楽を書き、人気の Mikmod ライブラリを使ってその音楽をゲームに組み込みたかったのです。「Mikalleg」という補助ライブラリは、サウンド出力ルーチンを Allegro のオーディオエンジンに接続し、Mikmod と Allegro が両方とも SAMPLE という構造体を定義している問題を回避するプリプロセッサのトリックを行っていました。
使いこなすのはやや複雑で、Mikmod / Mikalleg は多くの混乱したパラメータを持つ柔軟な API を提供していました。私はそれらが何であるかを理解する必要はなく、単に音楽を再生させる関数だけを欲しかったので、自分で値を見つけてラッパー関数を書き、あの柔軟性をすべて除去しました。
また、Mikalleg は Allegro の圧縮データファイル機能と互換性がありませんでした。私はそれを望んでいました。(本物のゲームは音楽ファイルを簡単に再生したり変更したりできるわけではありません!)Mikmod は汎用 I/O インターフェースを持っていたので、ファイル読み込みルーチンを「read」と「write」コールでオーバーライドできます。複雑そうだったので無視し、代わりに Allegro のデータ(既に解凍され RAM にロードされたもの)を何らかのディスクへ書き出し、Mikmod に読み込ませて削除する関数を書きました。理想的ではないと知っていましたが、うまく機能しました。
私はこのすべてを「Easymik」というライブラリにまとめ、ウェブページも作成しました。Mikalleg の作者はそのホームページからそれへリンクしてくれました!人々はデータファイルの問題に対する解決策を切望しており、私はそれを構築したのです。
私は本当に「リアルプログラマ」になりたかった。C とアセンブリで書かれた本物のプログラムを知っていました。実行ファイルがあり、DOS4GW が何故か必要で、特殊なデータフォーマットに特化したデータファイルが存在し、.S3M ファイルを再生できず、.PCX をペイントで開けず、テキストファイルを編集できない――そのようなものです。物事がこのようになっている理由はわからなくても、それに近づけばなるほど「リアル」になると信じていました。
もし私に「コードを書いてくれる魔法の箱」を与えてくれ、理解できないコードを生成し、動作するけど時々奇妙な問題が出るようにしてくれ、私はエリート的技術質問で煽り続けられて、合理的だが時には間違った答えを得られるとしたら、喜びの渦に包まれたでしょう。私は感謝の涙を流し、情熱的にコードを書き始めるはずです。確かにそれは下手ですが、私がアクセスできるすべてのリソースもまた下手でした。
しかし私はその道で行き詰まる可能性も知っていました。多くの年を無駄にすることもあったでしょう。しかしいくつかの出来事が私をより良い軌道へ導いてくれました。
最初の転機は、高校生の間に QNX でプログラミング職に就いたことです。私は C を十分に学び、ポインタや malloc/free の使い方を知っていましたが、スタックとヒープの違いを説明できるほどではありませんでした(同僚がその用語を投げつけた瞬間の恐怖は鮮明です)。
QNX は MS‑DOS や Windows とは全く異なるもので、シンプルでエレガント、理解しやすく信頼性があります。Rob Krten の本を読み、「これはオペレーティングシステムがあるべき姿だ」と自分に言い聞かせました。私は Win32 プログラムを書いたことはありませんが、Photon を把握できました。これにより、物事がそれほどひどくないと実感しました。
唯一の問題は「良い設計」を見つける方法を知らなかったことです。私が知りたかったのは、読み取っているアドバイスは意味不明で、誰もがあるルールに従うべきだと言うばかりでした。DSL、Lisp、Forth など、形としては実在するけれど「魔法」と語られる言語やツールに興味を持ちました。
次の職場では、新しい周辺機器をサポートするために数十個のカスタムツールをパッチするという憂いな作業を終えたばかりでした。これらは最後のものをクローンしてコードを書き換えるだけで構築されたもので、実際には2つしかユースケースがありませんでした。私はそれらすべてを置き換える単一の統合コードベースを提案しました。XML で無限に設定可能な汎用ツールキットを数か月開発し、80%は合理的に解決できましたが、残り20%ではシリアル番号文字列の構造を定義する双方向アルジブラを作るなど、奇妙な曲げが必要でした。私は恐れずに進め、最初のユースケースでかなりうまく動くものを完成させました。
しかしシステムを第二のユースケースに拡張した際、グリーンスポンの第十法則に違反していることが明らかになりました。私は任意のオブジェクトを保持できる動的 Value クラスを定義し、XML でバイナリログファイルのデータスキーマを動的に決めました。その結果、数百 KB のログを解析するだけで開発 PC が RAM を使い果たしました。最終的にはそれを最適化して実際に配布できるようにしましたが、私は手動でスキーマをハードコードすることに辿り着きました。私の構築したものは、統一された汎用コードベースに触れるすべての人がやはり製品固有のコードを書かなければならないという、避けたかったことを再びもたらしました。
私はさらに多くの時間を費やし、より良いツールこそ答えだと確信しました。ドメイン特化言語がすべての問題の解決策になると信じ、数千キロ離れたアメリカに移住し、億万長者から 5 年間木のマージアルゴリズムを修正できない仕事を得ました。
もしあなたが物事を正しく考えていなければ、一つの問題に何度も取り組むことは可能です。私はその職場で初めて、長年キャリアを通じて静かに私を駆動させていた恐怖――本当に掘り下げる恐れ、理解できないときに正直に認める恐れ、すべてがあまりにも複雑で扱いづらいという恐れ――に直面しました。私は長年探し求めた魔法のツールや不可能な技術を実際には学ばずに作ろうとすることの難しさを知りました。
問題を解く前に理解しなければならない。コンポーネントが期待通りに動かない場合、内部を掘り下げて本当に何が起きているかを調べる必要があります。重要であればそれは大きな過ちです。私はもうそのような無駄遣いを二度としたくありません。
物事の仕組みを理解することに専念すれば、すべてが容易になります。やればやるほど簡単になり、学ぶほど多くを成し遂げられます。これこそが私が半分のキャリアで探していた魔法のツールです。
私は Polya の How To Solve It からチェックリストを印刷し、仕事に取り掛かるたびに参照しました。本全体は読まず、数問だけでも十分でした。木マージアルゴリズムで進歩しており、ランダム化テストシステム(QuickCheck に似ているが縮小機能なし)でバグを発見し、データ損失やクラッシュの問題に直面せずに済みました。最終的にはコードベースの根本的な仮定に挑戦し、それらが私の仕事を不必要に難しくしていることに気づきました。それを解体し、再構築した結果、完璧に動作しました。
今日のソフトウェア専門家として私が提供できる最大の価値は「本当に何が起きているかを理解する力」です。時には基礎科学的な質問への回答も必要ですが、混乱しているコンポーネントのソースコードにまで潜り込み、本当にどう動作しているかを確かめることに満足できません。このスキルは年々重要性が増す一方です。
サスマンは90年代が電気・ソフトウェア工学で複雑さが爆発した時代だと正しく指摘しています。しかし、私はその間隔で私たちが完全に複雑さを制御できなかったとは思いません。Windows 95 アプリを書くのよりも今の状態が悪いと納得させることはありません。90年代ではすべての内部動作が秘密でした。Windows 95 のソースコードは手に入らず、ドキュメントでプログラミングし、バグや予期しない振舞いに直面した際には「何かを叩いて問題を止める」しか方法がありませんでした。カーネルデバッガーで逆アセンブルすることはほとんど人にとって実行不可能です。
しかし今日のソフトウェア開発者は別の状況にあります。巨大なライブラリがあり、今まで以上に多くがオープンソース化されています。期待通りに動かない場合、その理由を把握することはかつてよりずっと簡単です。ほとんどの場合、2025 年に使う価値のあるコンポーネントは一貫した設計原則に従い、通常その方法で動作し、学ぶのが可能です。もちろんまだゴミもあります—依存関係を慎重に選びましょう!—ですが90年代と比べれば選択肢は圧倒的に豊富です。
約10年前に Android UI プログラミングを行った経験があります。カスタム View を時折書き、UI レイアウトが再計算されないバグに悩まされました。ドキュメントは役に立ちませんでした。requestLayout や forceLayout の呼び出しを増やしても効果がありませんでした。
ついにソースコードを掘り下げ、Android が内部でどう動作するかを理解しました。実際には requestLayout はフラグだけ設定し、描画時に親へ再帰的に通知します。forceLayout は同じフラグを自分自身にしか設定せず、子が requestLayout を呼んだときの伝搬停止を意味しています。これらは「レイアウトバグを作る」ためだけに存在するメソッドです。データ競合もあり、レイアウト中に呼び出すとビューのフラグが不整合状態になり全体が狂います。
コードを読んだ後、Android のレイアウトアルゴリズムが実際にどう機能するかを理解できました。これでカスタム View を再設計し、問題を回避できました。奇妙な振る舞いも解明でき、実験や叩くことで得られる脆弱でバグの多いコードから脱却しました。
結局、複雑なソフトウェアは理解可能な単純な部品から構築できます。2025 年のプログラミングは暗闇でつまづく必要はありません。光を点ける準備ができていれば、すべてが容易になります。