ARCHITECTURE.md (2021): プロジェクト構造技術仕様書
(matklad.github.io)- 10k〜200k行規模のオープンソースプロジェクトでは、
README、CONTRIBUTINGの横に ARCHITECTURE ドキュメント を置くことで、新規コントリビューターがコード構造を把握するコストを下げられる - 不慣れなプロジェクトでは、パッチ作成がだいたい2倍遅くなることよりも、どこを修正すべきか を見つけるのに10倍以上かかる問題のほうが大きい
- この文書には高水準の構造と頻繁には変わらない内容を簡潔に載せ、コードと継続的に同期するよりも 年に数回 点検する運用が適している
- 中核となる構成要素は問題の俯瞰図と コードマップ(codemap) であり、大きなモジュールとその関係を示して「Xを担当するコードはどこか」に答えるべきである
- 重要な名前、アーキテクチャの不変条件、レイヤー・システム境界、横断的関心事は残しつつ、直接リンクより 名前検索 を促すほうが保守負担を減らせる
ARCHITECTURE ドキュメントが減らすコスト
- オープンソースプロジェクトでたまに貢献する人とコア開発者の最大の違いは、プロジェクトの 物理アーキテクチャ を知っているかどうかである
- 不慣れなコードベースでは、ファイルを無作為な順序に置かれた論理の断片のように順番に読んでしまう
- すでに意味のある貢献をした開発者は頭の中に コードの地図 があり、必要な場所へすぐ移動でき、なければ該当コードを移動させることさえできる
ARCHITECTUREファイルは、この隔たりを低コストで縮める手段である- 文書は短くあるべきである
- 繰り返し貢献する人は皆それを読む必要があるため
- 短いほど将来の変更で無効化される可能性が低い
ARCHITECTUREには頻繁に変わらない内容を載せることが基準である- コードと継続的に同期しようとはしない
- その代わり年に数回見直す
何を含めるべきか
- まず、プロジェクトが解決する問題を 俯瞰図 のレベルで整理する
- 続いて、ある程度詳しい コードマップ(codemap) を作成する
- 大きな単位のモジュールと相互の関係を説明する
- 「Xをするものはどこにあるか」に答えるべきである
- 「今見ているこれは何をするのか」にも答えるべきである
- 各モジュールの内部動作にまで深く立ち入らない
- その種の内容は別文書か、よりよい形としてインラインドキュメントへ移す
- コードマップは国家地図であって州別地図帳ではない
- コードマップを書く過程で、プロジェクト構造そのものも点検できる
- コードマップ上で近くに置きたいものが、
tree .の実行結果でも隣接しているか確認できる
- コードマップ上で近くに置きたいものが、
- 重要なファイル名、モジュール名、型名は明記する
- 直接リンクは時間とともに壊れる可能性があるため避ける
- 代わりに名前でシンボル検索するよう促せば、保守負担を増やさず関連する似た名前の項目も見つけられる
- アーキテクチャの不変条件 は明示的に書くべきである
- 重要な不変条件は、何かが「存在しない」という形で現れることが多い
- たとえばWeb開発で、モデル層がビューに依存しないという事実は、コードだけ読んでも分かりにくいことがある
- レイヤーとシステムの間の 境界 も示すべきである
- 境界は、その背後にあるシステム実装についての情報を示唆する
- 取り得るすべての実装まで制約する
- 良い境界はコードから無作為に見つけにくいため、文書化が有用である
- コードマップの後には、横断的関心事のための別セクションを追加する
- 参考になる例として、rust-analyzer の architecture.md を参照できる
1件のコメント
Hacker Newsのコメント
このアイデアは良いし、リポジトリの規模に関係なく、アーキテクチャの説明はREADMEにも載せる場所があると思う
たとえば、すべての読者がワークフローを見て理解できることが重要だと考えて、メインのREADMEにわざとMermaidのシーケンス図[1]を入れている[2]
[1] https://mermaid.js.org/syntax/sequenceDiagram.html
[2] https://github.com/hbcondo/revenut-app?tab=readme-ov-file#-w...
本当に良いアドバイスに聞こえる
実行中のシステムのアーキテクチャを可視化するツールがもっと良くなってほしい。いまだにコードを読むかMarkdownファイルを見るのが最新のやり方だというのは不思議だ。運が良ければMermaid図くらいはあるかもしれない
アーキテクチャが自らリアルタイムに姿を現してくれたらいいのにと思う。マクロな規模での可観測性がデフォルトで組み込まれているような形が望ましいし、そうなれば誰もがコンピューティングをよりよく理解できるし、人類が自分自身を拡張する助けにもなる気がする
一時的なコントリビューターが多いオープンソースプロジェクトには、保守負荷の低いモデルとして良さそうに見える。専任エンジニアがいるプロジェクトならADRも検討する価値がある
ADRはより保守が必要だが、「なぜそうしたのか」と「検討した代替案」を残せるので、再設計するときに非常に役立つ
参考: https://adr.github.io/
ARCHITECTURE.md は現在のアーキテクチャの状態を表し、ADR はそこに至るまでの意思決定の記録だ。どちらもとても有用
マイクロサービス、Kafka、Kubernetes: 現在のユーザーは4千人だが、もし10億人になったらどうするのかという理由
GraphDB: SQLで十分でなかったらどうするのかという理由
ElasticSearch: 統計とあわせて全文検索も必要になったらどうするのかという理由
しかしこうした文書の大半は結局、「面白いから新しいアーキテクチャ/技術を使ってみたい、FAANGに勤める同僚が使っている、その本を読んだ、履歴書映えする」の短縮形にすぎない
彼らが次の大きなプロジェクト設計に移ってしまった後、私たちのチームはチーム人数より多いサービスと上記のDB・技術を同期し続けなければならない。もちろん、こういう問題は「大きなアーキテクチャ判断」を下すよりはるかに単純だ、ということになっている
ふと思ったのだが、これまで使ったすべてのIDEは左側にプロジェクトのフォルダー構造を標準的なディレクトリツリーで表示する。プロジェクトを依存関係グラフとして探索できるIDEはあるのだろうか?
目次のような表現はあまり合っていないと思う。最近の自分のコーディングワークフローでは、ターミナルを開いてその中でrangerを実行し、左右のディレクトリ構造をたどるときはそのターミナルにタブを切り替える。VSCodeを開いて分割ターミナルにし、上側は普通のターミナル、下側ではRangerを動かす、という形だ。Midnight Commanderでもいいし、実際のところTUIファイルエクスプローラーなら何でもよい
さらに、プロジェクトのarchitecture.mdファイルにコードマップを入れ始めた。
tree -Lを実行すると、Markdownに入れるのにちょうどいいファイル構造ツリー図を好きな深さで得られる。その出力をMarkdownに追加し、各ファイル/フォルダーの後ろに10語未満で用途を説明する注釈を付けるRanger - https://github.com/ranger/ranger
Midnight Commander - https://midnight-commander.org/
どんな形になるかについて、2つアイデアがある
1つ目は、シンボリックリンクを使ってファイルを直交的に整理する複数のディレクトリツリーだ。一般的なディレクトリ構造はクライアント/サーバーで分かれるが、機能ベースで分けたいとしたらどうだろう? IDEならもっと簡単に実現できるはずだ
2つ目は、この記事の方向性のように、IDEがブックマークを作ってその間を行き来し、人にコードを説明しやすくしてくれたらいいということだ。ときどきコメントを残して、クリックするとコードベース内の別の場所へジャンプしたい。そういうものをつなぎ合わせれば、コードベース全体にわたって動作を説明する物語を編める
こういう方向で作業している人がいるのか気になる
ここで著者が言っていることを一般的なソフトウェアプロジェクトにまで広げすぎるのは注意したほうがいいと思う
文脈が不足したコントリビューターの多い大規模オープンソースプロジェクトでは、こういう文書を維持する価値は大きい。しかし小さな業務プロジェクトでは、開発者がコミットした文書は結局どれも保守されない状態になるのを見てきた
少なくとも、チームメンバーが現在のアーキテクチャと理想のアーキテクチャについて互いにまったく異なる考えを持っていることが分かる。それを明示的に表に出すだけでも文書を作る価値がある
そして「文書は保守されない」というのは、文書を作らない理由としては非常に弱い。どんな文書でも、古くなっていたり微妙に間違っていたりする文書であっても、「文書がない」よりはましだからだ
数年前、大きめのサイドプロジェクトの1つで似たようなやり方を試したことがある
https://github.com/shipmight/shipmight/blob/master/src/ARCHI...
各ファイルの先頭には、リポジトリ内の別の
ARCHITECTURE.mdファイルへ移動するためのリンクツリーを置いていた。例は次のとおり:ARCHITECTURE.md<- 現在位置、backend/ARCHITECTURE.md、backend/api/ARCHITECTURE.md、backend/cli/ARCHITECTURE.md、backend/ui/ARCHITECTURE.md、backend/utils/ARCHITECTURE.md、frontend/ARCHITECTURE.md、internal-charts/ARCHITECTURE.mdREADME.mdを置くと、GitHub UI がファイル一覧の下にレンダリングしてくれるこういう場所で見える形: https://github.com/shipmight/shipmight/tree/master/src/backe...
いくつかのプロジェクトでもこのやり方を見たことがある
短いほど、将来の変更で無効化される可能性が低い。ARCHITECTURE の中心的な経験則は、頻繁には変わらないことだけを書くことだ。コードと同期させようとしてはいけない
インターフェースは変わる可能性が低く、変更もしにくい。これはシステムをモジュールに分解するときに使う基準に関する Parnas の考え方だ
コードベースを理解しにくいという点には同意する。「パターン」に名前を付けることはある程度役に立つが、結局かなり読まなければならない
GitHub では、ファイルごとのコミットメッセージが説明のように感じられることが多い。それのほうが有用だったりするだろうか?
参加したすべてのプロジェクトで、オンボーディング時にアーキテクチャ図と構成要素についての簡単な説明を受けた
だから、オープンソースでこれがそれほど一般的でないのは驚きだ
オープンソースプロジェクトには社員の初出勤日がないので、こうした紹介もない
時間がよほどたくさんない限り、こうした説明はあまり良くない。社員なら1人で何かをやれるようになるまで数週間かかると期待されるが、セキュリティコンサルタントである私たちは2週間ごとにまったく新しい説明を聞くことになる。問題は、こうした説明が即興的で構造化されておらず、話す人が知識の呪いのせいで無関係な詳細をたくさん話してしまうことだ
おそらく、リポジトリに新しく来た人が一度これを書き、その後は保守だけするのがよい。次善策は、毎回その場しのぎで誰かが説明する代わりに、何を入れて何を省くかを1分ほど考えてから書き留めておくことだ。著者が言うように、このファイルはプロジェクトの高水準アーキテクチャを説明すべきで、短くあるべきだ。継続的なコントリビューターは皆読むべきであり、短いほど将来の変更で無効化される可能性も低い
いつもとても有用な実践だと感じていた。多くのプロジェクトには、変更の大半が発生する中核ファイルがいくつか、あるいはパッケージ/モジュールなどがある
新しいコントリビューターや久しぶりに戻ってきたコントリビューターがそれらを素早く把握できれば、プロジェクトの立ち上がり時間を大きく短縮できる
いくつかの職場でプロジェクトにアーキテクチャファイルを追加してみたことがあり [0]、[1]、反応は良かった。完璧ではないが、ないよりはましだ
[0]: https://github.com/zapier/zapier-platform/pull/324
[1]: https://github.com/stripe/stripe-cli/blob/master/ARCHITECTUR...
以前は、こうした小さなドキュメント/ダイアグラム-as-code 標準が好きだった
README 主導開発、
ARCHITECTURE.md、ADR、arc42、C4 などだ今は、git リポジトリの
/docsフォルダの中に Obsidian の保管庫を入れている他人の標準を使う代わりに、Obsidian で個人ノートを管理するようにドキュメントを継続的に整理してリファクタリングしている
最初は GitHub の GFM と Obsidian の両方で動く共通の Markdown サブセットを使いたかったが、あきらめて、今では Dataview プラグインやテンプレートのような独自機能も含めて Obsidian 形式の Markdown をそのまま使っている
Mermaid と LaTeX は Obsidian に組み込まれており、PlantUML プラグインもある。視覚的な図/ダイアグラムには組み込みの Canvas、DrawIO、Excalidraw を使っている