Markdown を /src に置く
Carson Gross は、Markdown がドキュメントからソースコードへ変わりつつあると考え、生成されるコードの隣(/src)にコミットすべきだと主張する。コードもテストも Markdown から派生させる。
日本語
コピー
TLDR
- Markdown はドキュメントではなく、ソースコードになりつつある
- そうした Markdown は、それが生成するコードと一緒に
/srcにコミットすべきだ - コードとテストは、一時的な prompt からではなく、この Markdown から派生させるべきだ(少なくとも、prompt のセッションはいずれ永続化された Markdown に落ち着くべきだ)
はじめに
Montana State University で教授を務める給料を補うため、外でコンサルティングをしている。コンサルティングは好きだし、コードを書いたりシステム構築を手伝ったりするのも好きだ。それ自体が面白いからでもあり、自分のスキルを錆びつかせずに済み、学生にソフトウェア開発の最新の考え方を教えられるからでもある。
ここ数年で開発の世界で起きた最大の変化は、明らかに agentic coding だ。手書きのコードを LLM による生成で置き換える。これについてはいくつか記事を書いてきた。
この記事で話したいのは、agentic coding を最優先する会社で働く中ではっきりしてきた一つの考え方だ。
Markdown は今やソースコードであって、ドキュメントではない。
もちろん、目新しい話でもなければ、特に賢い話でもない。
Markdown is the new source code の中で、Hartley Brody はこう書いている。
ソフトウェアのアプリケーションロジックは markdown で定義・編集されるようになりつつあり、agent が実際に生成するコードは、ある意味で下層の実装詳細になりつつある。
上の記事からも分かる通り、私は AI が生成するコードに対して複雑な思いを抱いている。ただ、コンサルティングの仕事を通じて見えてきたのは、組織がこの方向へ、しかも往々にして驚くほど速く動いているということだ。
ここからは、Markdown がソフトウェアシステムの信頼できる情報源になりつつあるとき、それが何を意味するのかを考えたい。
欠けているソースコード
上の引用が象徴しているのは、こういう考え方だ。LLM はコンパイラのようなもので、高水準の仕様を低水準の実装に変換する。この見方に立てば、LLM が生成したコードを読む必要はない。コンパイラが生成したマシンコードを読まないのと同じだ。
Code is Cheap(er) でも触れたが、私はこの類推に完全には賛成していない。理由はいくつかあるが、この記事に関係するのはこれだ。コンパイラのワークフローは元のソースコードを保持するが、LLM のワークフローは通常それを保持しない。
今どきの LLM 生成コードは、開発者が機能を実装するときに、一連のプロンプトで agent に食わせて出てきたものだ。実際には、生成されたコードがその機能の「ほぼ基準となる真実」になる。機能のドキュメントは別の場所(Linear、Slack のスレッド、wiki など)にあるかもしれないが、コードベースにとっては、生成されたコードが事実上の情報源だ。
私の考えでは、プロフェッショナルな agentic プログラミングの現場では、一時的なプロンプトセッションから生まれた LLM 生成コードは理想的ではないという現実を受け入れ、ソースディレクトリの中で Markdown を生成コードと一緒に記録しコミットする方向へ移るべきだ。
Markdown はソースコードである
Markdown には、従来のソースコードに似た優れた性質がいくつもある。
- プレーンテキストなので diff も grep もでき、pull request でレビューできる
- LLM がネイティブに読み書きできる
- 人間がツールなしで読めて編集できる
実際、AGENTS.md や specs、plans、TASK.md など、Markdown はすでにある程度ソースコードとして機能している。ただ、そうしたソースコードの記録を標準化していないだけだ。
Markdown is the new source code の中で、Brody は仕事のとき Markdown ファイルを .scratch/research/ と .scratch/plan/ に置いていると書いている。私も似た慣習に従い、一時的な要件のために /tmp ディレクトリを作っている。
私の提案は、そのうちのいくつかのファイルを、既存のソースコードと並ぶ新しいディレクトリに格上げすることだ。/src/md
この提案ディレクトリに記録される Markdown は、従来の設計ドキュメントより低水準になる。
- アーキテクチャの決定を含む
- ソースコード水準の決定を含む
- 低水準のデータ設計の決定を含む
これは仕様(とはいえ、そう呼べるものでもないが)に近く、プロジェクトマネージャーやデザイナーが従来のやり方で管理する設計ドキュメントとは違う。
局所性
私は局所性の信奉者で、Markdown を /src に置くことには強い利点があると考えている。
- コードモジュールが、そのコードの意図を説明する Markdown を抱えるようになる
- 奇妙な「リモート仕様」がなくなる。なぜそう書いたかの論理が wiki/Notion/Confluence/Jira のどこかに散らばることがなくなる
/srcの Markdown を、人間と agent の両方が消費できる- agent は、あるコードベースの文脈を求めて他所を探し回らなくて済む
では Linear/Wiki などは?
システムの振る舞いに関する他の情報源は、引き続き存在してよい。それらはより高水準の、いわば「プロセス寄り」のドキュメントを提供する。高水準の設計ドキュメントや、プロセスを必要とする issue などだ。
しかし、システムの中核となる、現時点での静的な期待動作は、ますますソースコードのディレクトリ内の Markdown に直接書かれるようになるだろう。
ではテストは?
ネット上では、テストこそが新しい仕様書だ(あるいは昔からずっとそうだった)という意見をよく見かける。一理あると思う。
ただ、テストは人間と機械のやり取りの仕組みとしては優れていない。
- 儀式的な要素が多く、実際に何をテストしているのかが見えにくくなりがち
- 一般に、特にシステムを理解しようとするときには、多くの人が扱いたいと思うよりも低い抽象度にある
- Mermaid 図のような高レベルな説明を自然に組み込めない
次のような役割分担が妥当だと考える。
- Markdown を
/srcに置き、(おおまかな)仕様書とする - テストを
/test(あるいはどこでも)に置き、その Markdown を根拠に、自動化された正しさの確認を提供する
繰り返すが、中心となる考えはこうだ。開発者は prompt でコードとテストを生成するのではなく、/src ディレクトリに Markdown を書き、コードとテストはそこから派生させる。
/src/md の Markdown とはどんなものか
/src/md の Markdown は、システムの形式的な仕様書と高レベル設計ドキュメントの中間に位置する。
ソースコードと同じく、これらの Markdown にも複雑度の予算がある。ドキュメントをクリーンに、適切に分解された状態に、適切な抽象度で保つには、意識的な管理が要る。
開発者は Markdown と、そこから派生したコードの両方に触れることになる。したがって、適切なタイミングで両者を同期させることは重要なスキルになる。
たとえば開発者は、生成されたコードに減算的で制約的な修正を加えることがよくある。そうした変更は Markdown 側に書き戻す必要が生じるかもしれない。
/src/md の中身の大部分は agent に生成させるべきではないと考える。このディレクトリは主に人間が書き、維持するものだ。
/src/md の規約案
この部分は間違いなく本記事で最も弱い。新しいアイデアであり、まだ大量に使ったことがないからだ。考えながら話しているだけの、議論の叩き台である。
とはいえ、/src/md の標準案はこうなる。
src/
md/
README.md # index of all md, entry point for agents
TODO.md # a list of general TODOs open for this module
OVERVIEW.md # a technical overview of this module
features/FEATURE_1.md # a set of feature-specific documents
data/DATAMODEL_1.md # descriptions of data models in the module
api/API_1.md # descriptions of APIs the module provides
infrastructure/INFRASTRUCTURE_1.md # descriptions of infrastructure used by the module
features、data、api、infrastructure の各ディレクトリはすべて任意だ。異なる軸で分割し、/src/md フォルダ内でモジュールの振る舞いについて、確かな使える記述を直接与えるのが狙いである。
結論
コードの生成コストがどんどん下がると、価値が残るのはコードの背後にある意図だけになる。何をするのか、なぜそうするのか、そして絶対にしてはならないことは何か。
今日、その意図は使い捨てのプロンプトセッションの中に散らばっていたり、wiki やチケット、Slack のスレッドに断片的に散らばっていたりする。
局所性を考えれば、その意図を Markdown で記録し、それが生成するコードと一緒に /src にコミットして、人間にも agent にも見つけられるようにすべきだと考える。
/src/md のようなものの正しい構造がどうなるのかは、まだ分からない。私自身(そして他の人たち)が経験を積むにつれて、考えも変わっていくだろう。
ただ、Markdown がソースコードになりつつあり、私たちもそれをますますソースコードとして扱うべきだということには、かなり確信がある。
(とはいえ、そう、LLM はコンパイラではない :))