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

ソフトウェアアーキテクチャの学習

概要

  • ソフトウェア設計 は実践を通じて学ぶもの
  • 組織構造とインセンティブ が設計やコード品質に大きく影響
  • 科学コードと産業コード の違いは知識よりも動機や制約の違い
  • 具体的な設計例 としてrust-analyzerの経験を紹介
  • 推奨リソース や学び方のアドバイスも記載

研究者物理学者がソフトウェア設計を学ぶには

  • ソフトウェア設計 は「実際に手を動かす」ことで身につけるもの
    • 大学の「設計」科目やプロジェクトは、現実の課題解決とは異なる経験
    • 本当の学びは、実務やリーダー的立場での失敗と成功から得るもの
  • ソフトウェア工学 は好奇心があれば独学でも習得可能
    • ブログ記事や実践から原理を学ぶことも十分可能

組織構造とインセンティブの重要性

  • Conway’s Law :「ソフトウェアの構造は組織の社会構造を反映する」原則
    • コードよりもアーキテクチャ、アーキテクチャよりも社会的要因が重要
  • 産業用と科学用ソフトウェア の違いは「知識」より「インセンティブ構造」
    • 例:「3ヶ月で論文を出す必要がある」などの外的要因
  • インセンティブ構造 を設計できるタイミングは稀だが、非常に重要な機会
    • TIGER_STYLEの本質もこの社会的文脈に依存

制約下での最適化と適応

  • 理想的なインセンティブ構造 はほぼ存在しない
    • 変えられない場合は「受け入れて適応」する能力が重要
  • 産業プロジェクト でも常に「制約下で最良を目指す」姿勢が求められる

rust-analyzerの設計経験

  • プロジェクトの物理的現実 :「深さ」と「広さ」を兼ね備えた設計
    • 深い部分(コンパイラ)は少数の熟練者向け
    • 幅広い機能(IDE特有)は多くの短期貢献者向け
  • 貢献しやすさの工夫
    • rust-analyzerはrustc不要・C依存なし・テスト高速化で敷居を下げる
    • 各機能は独立性を高め、catch_unwindで障害を局所化
    • コア部分は品質管理を厳格化、機能部分は「動作すればOK」で柔軟に対応
  • 設計の意図と現実
    • LSPのアーキテクチャ改善が目的だったが、最終的にコンパイラが一つ増えた結果に
    • uutilsも同様に、学習用から本格的なシステムへと変化

学び方とおすすめリソース

  • 唯一無二の良書 は存在しない、実践こそが本質
    • Borgesの短編小説にしかないような「真理の書」は現実にはない
  • 注目すべきリソース
    • Gary Bernhardt「Boundaries」:オブジェクト設計とメタ思考
    • 「How to Test」:実用的なテストの考え方
    • Pieter Hintjens「∅MQ guide」およびConway’s Lawの解説
    • Jamii「Reflections on a decade of coding」:メタ視点の経験談
    • Ted Kaminski blog:ソフトウェア開発理論のまとまったノート
    • 書籍では「Software Engineering at Google」「The Philosophy of Software Design」も推奨
      • 特に前者は用語理解に役立つが、決定的なブレークスルーではない

まとめ

  • ソフトウェア設計力 は「実践」「適応」「社会的文脈理解」で磨かれる
  • 書籍や理論 よりも、現場での経験とフィードバックの蓄積が重要
  • インセンティブ構造や組織文化 への理解が、設計や開発の質を左右

Hackerたちの意見

これを見て、古代中国哲学における孔子と老子の学びの知恵を思い出したよ。孔子は学びを「育成」として捉えていて、教えられたからって本当に知っているわけじゃないって言ってる。実際にやってみたり、反省したり、失敗したりしながら、徐々に判断力を育てていくんだ。老子はそれに対して補完的な警告をしていて、「学びを追求するには、毎日何かが加わる。道を追求するには、毎日何かが削ぎ落とされる」と言ってる。マスタリーは単なる蓄積じゃなくて、不要な抽象や儀式、巧妙さ、コントロールを取り除くことでもある。ソフトウェアアーキテクチャには両方が必要みたい。孔子的な意味で、実際の仕事をして、その結果と共に生きることで学ぶ。道的な意味では、システムが人々やインセンティブ、制約に合わなくなった構造を蓄積していることに気づくことで改善していく。だから、この記事のインセンティブについてのポイントが響くんだ。アーキテクチャは、単に紙の上でデザインするものじゃなくて、それを生産し維持する組織との接触を経て生き残るものなんだよ。

「コードオン、コードオフ」

老子はそれに対して補完的な警告をしていて、「学びを追求するには、毎日何かが加わる。道を追求するには、毎日何かが削ぎ落とされる」と言ってる。マスタリーは単なる蓄積じゃなくて、不要な抽象や儀式、巧妙さ、コントロールを取り除くことでもある。うーん、君(または君のLLM)の解釈は元のものより少しニュアンスが足りないかも。君が言及した『道徳経』の詩は、手放すことやシンプルな生活を送ることについてのもので、実際には世界の複雑さを扱うために適度な複雑さが必要なプログラミングとは少し逆の考え方だよ。余談だけど、たとえ英語が母国語でなくても、LLMのサポートなしで考えをまとめようとするのは大歓迎だよ。

こう考えてる。ソフトウェアアーキテクチャは教えられない。 (これは特に珍しいことではなく、特別な主張ではないけどね。) でも、人々が直面する問題や考慮すべき解決策に気づかせることはできる。 「10のソフトウェアアーキテクチャの良さを持つ」ソフトウェアアーキテクトに「教える」ことはできないけど、彼らがSAGUを蓄積する速度を加速させることはできる。 実際、私の言う通り、ほとんどのことはこういう風に機能すると思う。 人を拾い上げて、5年や10年の経験を与えることはできない。 できるのは、車を渡して道を示すこと。ジャングルをマチェットで切り開くのではなくね。 私の教育方法への大きな批判の一つは、システム内のほとんどの人が、数百時間話すだけで、魔法のように完成されたスキルを持つようになると信じていること。 「教育された」状態に人を落とし込もうとすることに焦点を当てすぎている。 もちろん、旅は非常にガイドされ、構造化されるべきだけど、道をクリアにすることはできても、学生のために一歩を踏み出すことはできない。 「それはまた、不要な抽象、儀式、巧妙さ、コントロールを取り除くことでもある。」 これを聞くと、ソフトウェアアーキテクチャに対する最も顕著な脅威の一つを思い出す。 ヘキサゴナルデザインやクリーンアーキテクチャ、MVC、あるいは他の「すべてのアーキテクチャへの答え」を厳密に守り、 それに従わないシステムは即座に再設計が必要な悪いシステムだと主張する人。 ソフトウェアアーキテクチャのような複雑なものに対する「答え」は本に収まらない。 実際、人間の頭にも収まらない。ネットワークサーバーの経験があっても、市場で競争できる高性能ゲームエンジンを設計する自信はない。 どうやってやるかのアイデアはあるけど、その分野で活動している人たちが知っている詳細をすべて知っているわけじゃないし、その詳細が重要になることもある。 誰もがすべての状況や条件下でソフトウェアを設計する方法を教えるほどの経験を持っているわけじゃない。 実際にアーキテクトとして活動している人は、そのことを心に留めておくべきだし、過去の経験を参考にすることは「車に乗って道を進む」ことの一部だけど、 祝福された答えのセットは常に目の前のタスクを通じて仲介されるべきで、逆ではない。

ガリー・バーンハートのトークは本当に特別だね。いろんな概念があって、他の面白いところに導いてくれるよ。

自分が関わっているプロジェクトのメンタルモデルをもっと身につけたいんだけど、プログラミング言語や特定のアーキテクチャの選択、あまりにも複雑で時間の無駄に感じることが嫌いになると、すごくやる気がなくなっちゃうんだ。プロジェクトによるけど、「フルスタック開発者」として働くのはプログラミングの楽しさを奪ってしまう気がする。想像できる中で最も退屈なプロジェクトを見ながら、週に40時間も費やしてるんだよ。

プロジェクトのメンタルモデルを得ることにもっと時間を使いたいけど、プログラミング言語や特定のアーキテクチャの選択、 あまりにも複雑で時間の無駄に思えることが嫌いになると、すごくモチベーションが下がる。 手放そう… どんなプロジェクトにも欠点はある。 一つもないよ。正直、プログラミング言語がそんなに重要なら、さっさと別の道に進んだ方がいい。 みんながポリグロットになるべきだけど、それは君次第だね。

もっと感情のコントロールが必要そうだね。

おすすめの本はたくさんあって、例えばオースターハウトの『ソフトウェアデザインの哲学』はすごく良いけど、ソフトウェア開発全般についての話で、特にソフトウェアアーキテクチャに特化しているわけじゃないんだよね。それについては、クラシックなテキストをおすすめするよ。例えば『ソフトウェアアーキテクチャ:新興分野の視点』(ショー/ガーラン)や、メアリー・ショーの著作は何でも読んでみてほしい。最近の論文も含めて、ソフトウェアアーキテクチャの分野が予想通りに進まなかった理由を探るものもあるよ。例えば『神話と誤解:プログラミング言語とは何か?』や『ソフトウェアアーキテクチャの抽象を再考し、それを支えるツール』など。もっと実践的には、Unixのパイプやフィルター、RESTが成功した理由や、どこでつまずくのかを見てみるといいよ。ヘキサゴナルアーキテクチャも重要だし、僕の貢献として、ソフトウェアアーキテクチャをメタオブジェクトプロトコルと結びつけてプログラミング言語やプログラミングの新しい基盤にするという提案もあるよ。『手続き呼び出しはコンポーネントの接着剤:コネクタはメタクラスの地位に値する』という論文で、メアリー・ショーの『手続き呼び出しはソフトウェア相互接続のアセンブリ言語:コネクタはファーストクラスの地位に値する』に対する回答でもあるんだ。手続き呼び出しがアセンブリ言語なら、高水準言語はどんな感じになるのか? そして、ソフトウェアアーキテクチャにはもっと明るくて実践的な未来があるかもしれないね。

手続き呼び出しがアセンブリ言語なら、高水準言語はどんな感じになるんだろう? PLTやSWEのツールには詳しくないけど、ラムダ計算、LISP、APL、Clojure、TCLあたりが基本概念じゃない? いくつかのデータ構造と型、基本的な関数の小さなコレクションがあれば、それを組み合わせるだけ。 Lispの好きなところは、複雑な型が常に不透明なところ(特にFFIのやつ)。 Cのような言語でCLOSの実装を見てみたいな。構造体を定義すると、標準的な関数のコレクションが得られる感じで。

いい読み物だった。「ソフトウェアアーキテクチャを学ぶ」ということは、単一の正解がないことを理解することだね。これはアートでもあり、サイエンスでもある。おすすめの読み物:『ITを簡素化する - よりシンプルなITソリューションへのアートとサイエンス』 https://nocomplexity.com/documents/reports/SimplifyIT.pdf

誰も「残余性」について触れていないのが驚きだね(https://www.architecture-weekly.com/p/residuality-theory-a-r...)。これはアーキテクチャ(デザインとは違う)についての非常に興味深い見解で、僕自身の経験とも一致している。著者は本(https://leanpub.com/residuality)だけでなく、アーキテクチャの哲学についての本(https://leanpub.com/architectsparadox)も出しているよ。

チートシートを教えるね:

  • 良いデザインは、一つのアイデアが全体に浸透していること。
  • 一般的には、驚きを最小限に抑えるのが目標だよ。
  • システムがそれを許すなら、人は必ずやる。
  • みんながただやるわけじゃない。「みんながただ…」で始まる解決策は、解決策じゃないよ。
  • データを変換する部分と、それを使う部分を分けて考えよう。データモデルはコードよりも長生きするからね。
  • 結合度はほとんどの悪の根源。
  • バージョン管理は避けられない。
  • 状態を明示的にしよう。
  • すべての情報には、単一の真実のソースが必要。
  • 物事の名前を正しく考える時間をもっと使うべき。
  • テストが難しいなら、デザインが間違ってる。
  • ドキュメントなしの決定は後悔することになるよ。
  • コミュニケーションは税金みたいなもので、支払う前に正当化すべき。 エンジニアの仕事は、どんなレベルでも、不完全な情報の中で問題を解決するための経験則を使うことだよ。

追加したいことがあるな。

  • データ移行は避けられないし、計画しておくべき(バージョン管理の副産物)。
  • 計画は大事だけど、時には試してみることも必要。
  • すべてにはコストがかかる。コストを考えずにデザインすると、後で厳しい選択を強いられるよ。

いいリストだね!ありがとう!

シェアしてくれてありがとう!#2には本当に同意するけど、最終的には完全に排除することはできないよね。

最後のやつ、もう少し詳しく説明してくれる? アーキテクトが避けるべきコミュニケーションのタイプは何? それ以外は、とても賢いリストだね!

いいリストだね!一つ追加したいんだけど、* モジュラーモノリスから始めるのがいいよ。

コミュニケーションは、支払う前に正当化すべき税金だ。 > すべての情報には単一の真実のソースが必要だ。 - できるだけ単一のシステムでやって、状態の共有を最小限に抑えよう。 - すべてのシステムは分散型であることを認識しよう。どうやってどこで分散するかの問題だ。現代のソフトウェアシステムで最も大きな問題の一つは、マイクロサービスのようなものに完全に傾倒してしまい、複数の相互依存する部分間で状態を同期させる必要があることだと思う。抽象化がどれだけクリーンでも、APIがどれだけ契約されていても、すべてのコピーや状態の同期を行うことは、パフォーマンスの問題、コストの問題、同期の問題を引き起こすことになるよ。

  • 状態を明示的にする。状態を複数の場所に保存しないこと。

ビールを奢ってあげたいくらい、すごく共感できるよ。もう1年以上、ビデオゲームを作ってるんだ。でももっと重要なのは、持続可能なエンジンを作っていて、明確なデータパイプライン、リソースのレンダリング/管理層が完全に分離されていて、実行可能な状態変換モードの明示的なカタログがあるってこと。正直、あなたのリストのほとんどが本当に当てはまるよ。たとえソロでも、エンジンの制約が忘れっぽい自分を「テストから生まれたこの変な新機能を追加するにはこうするんだ」って導いてくれるから、「特定の状態変換で何度も実行される新しい効果音を作りたいなら、こうやってやるんだ」っていう本を持たなくても済むんだ。乾杯!

この人は本当に何を話してるか分かってるね。でも、彼が積み重ねてきた経験やデータを伝えるっていうよりは、「知ってる人は知ってる」って感じがするな。言わせてほしいのは、たくさんの人が建築って、複雑なシステムをどうやって作るか(データベース、キュー、スケーリング、冗長性、フェイルオーバー、数十のサービス)だと思ってるけど、専門的な建築っていうのは、どうやって最小限のもので問題を正しく解決するかを答えられることだと思う。天才レベルのエンジニアリングは、どこでも使える軽量で安価、頑丈で簡単に作れるジッパーを発明することだよね。(彼が言ってるのは、企業がコンウェイの法則に従って、チームの数に合わせて多くの作業を社会的に構築するから、完全に不必要な複雑さの悪夢を生み出してるってことだと思う。)

[遅延]