ディスカッション (11件)
AIがコードを書く「エージェント時代」が到来した今、ドナルド・クヌースが提唱した『文芸的プログラミング(Literate Programming)』を改めて見直すべき時が来ています。人間がコードの意図や論理を自然言語で語り、AIがそれを形にする。この古典的なアプローチこそが、AIとのより良い協調や、生成されたコードのメンテナンス性を高めるための鍵になるかもしれません。
LLMは言語のモデルなんだから、文章を分かりやすく書くことに投資するのはめちゃくちゃリターンが大きいよね。いわゆる「文芸的プログラミング(literate programming)」が必須かどうかは分からないけど、適切な名前、docstring、型署名、意図(why)を説明するコメント、まともなREADME、それと思慮深く設計された抽象化があれば、しっかりしたパターンを確立するには十分。ガチの「文芸的プログラミング」までは必要ないかもしれない。むしろ「コミュニケーションへの注力」と言い換えたほうがいいかも。ノートブックやサンプル、スクリプトなんかは、パターンを補強するのにすごく役立つ。結局のところ、人間とLLMの両方が従うべきパターンを確立することが大事なんだ。
最近の傾向として、人間を助けるための習慣(まともなREADMEや設計書を書く、正確で曖昧さのない言葉を使う、文脈を提供する、文芸的プログラミングなど)は「手間がかかりすぎる」って理由で敬遠されてきた気がする。でも、人間の代わりにLLMを助けるためとなると、急にみんなやる気を出して努力し始めるのが面白いよね。
Orgは知らないけど、Rakudoc(https://docs.raku.org/language/pod )は文芸的プログラミング(ソースコード内にドキュメントを置く)にも、LLMにとっても便利だよ。コードが「自己文書化」されるから、LLMの制御反転において、LLMがどうやってコードを呼び出すべきか判断できる。https://podlite.org はこれを言語に依存しない形(今はPerl、JS/TS、Raku)でやってる。例を挙げておくね: #!/usr/bin/env raku =begin pod =head1 NAME Stats::Simple - Rakuで書かれたシンプルな統計ユーティリティ ... (中略) ... sub mean(*@values --> Numeric) is export { die "No values supplied" if @values.elems == 0; @values.sum / @values.elems; } ...
テストコードとプロダクションコードを対称的なペアにするのはメリットが多いよね。複式簿記みたいなもので、コード自体の視点と、それが正しく動くことを証明するコードの視点の両方から挙動を確認できる。テストかプロダクションコードのどちらかを変えて、もう片方をそれに合わせることでコードを変更できるし。コードレビューも楽になるよ。プロダクションコードで混乱してもテストコードに説明があることが多いし、その逆も然り。必要に応じて切り替えればいいだけ。メリットはたくさんあるけど、デメリットはもちろんコードの量が増えること。可読性の向上がそのコストに見合うかどうかは自分次第だね。
ここ10年くらいの自分のコーディングは、ほぼすべて文芸的プログラミングスタイルだよ。nbdevを作ったんだけど、これのおかげでノートブックを使ってソフトウェアの開発、ドキュメント化、テストができている。ここ数年はLLMをノートブックとnbdevに統合してSolveitってツールを作って、うちの会社の全員がほぼすべての業務(法務や人事まで!)で使ってる。文芸的プログラミングは、単なるプログラミング以上のことに役立つってことが分かったよ。
面白そうで、ちょっと関連するアイデア:LLMを使って、コメントやドキュメントがコードとズレてきた時にフラグを立てるっていうのはどうかな。ドキュメントの大きな問題は、書いた時点では正確だったとしても、時間が経てばコードに対して古くなってしまうこと。コンパイラなら型と実装の不一致を教えてくれるけど、これまではコメントがまだ正しいかどうかを自動でチェックする仕組みがなかった。これ、誰かスタートアップにできるんじゃない?
フルな文芸的プログラミングはやりすぎだと思うけど、自分はこれの軽量版をやってる:・モジュールレベルのコメント:モジュールの目的や、コードベース全体の中でどう機能するかを説明。・すべてのメソッド、定数、変数をドキュメント化:パブリックかプライベートかに関わらず。簡潔な一文で十分、凝る必要はない。・各コードブロックをドキュメント化:これも一文でOK。目的は、コードを「解読」しなくても、普通の日本語でそのブロックが何をしているか分かるようにすること。コードを読むのは、人間の言語を読むのとは別の能力だからね。
文芸的プログラミングの軽量版と、APIサーフェスは小さいけど規約が重視される言語の組み合わせは、この「エージェンティック・プログラミング」の時代に流行ると思う。APIの足跡が小さいってことはボイラープレートが増えるってことでもあるけど、LLMはボイラープレートを吐き出すのが大好きだからね。最近はPythonやTypeScriptみたいな動的言語より、Goをよく使ってる。エージェントがプログラムを書くなら、十分速い言語で書いたほうがいいからね。コンパイルが速ければ、エージェントは設計のイテレーション、実行、ループを素早く回せる。Goのエコシステムはスタイルガイドやデザインパターンがしっかりしてる。言語自体がnilポインタエラーみたいなミス(footguns)を完全に防いでくれないから、みんなパターンに頼る。エージェントはそういうパターンを拾うのが得意なんだよね。
自分は懐疑的だな。・自然言語は曖昧だ。だからプログラミング言語が作られたわけで、コード周辺のドキュメントも大抵は曖昧。さらに悪いことに、実行されないから古くなってしまう。・LLMはコードの翻訳は得意だけど、プロンプト(自然言語)をコードにするのはそこまで上手くいかない。・これって「悪いコード vs 良いコード」の問題じゃないかな。クソコードにドキュメントがあれば助かるけど、良いコードはそれ自体で意図を表現する。至る所にコメントが必要なら、それはコードの質が低いってことだと思う。コードの質が年々低下しているからドキュメントの必要性が増している、っていう議論はあるだろうけどね。
同じことを考えてた。もっと大げさな視点かもしれないけど、LLMのプロンプトこそが「コード」なんだっていう考え方。結局、プロンプトはLLMによって低級言語(実際のコード)に「コンパイル」されるテキストなわけで。コンパイルプロセスはやり取りが発生して少し複雑だけど、一方でめちゃくちゃハイレベルだ。目標は、プロンプトのネットワークがソフトウェアの「正解(source of truth)」になること。コードベースを記述するフローチャートが、そのままコードベースそのものになる、みたいな感じかな。