Applibot Advent Calendar 2025 の10日目の記事です。
前日の記事は @h_km さんのClaude Code × MCP でデイリーノートを自動生成 - 朝の情報収集を30分→3分に短縮した話でした。
はじめに
GitHub Copilot, Cursor, Claude Code, Antigravity ... なんでもいいですが、「前と同じように実装して」とAIに指示したら全然違うコードができちゃった!!という経験は誰にでもあると思います。
この記事では、AIがもてはやされる時代だからこそ、「従来のプログラム」とAIをうまく使い分ける必要があるよね、ということをつらつらと書いていきます。
AIに絶対はない
AI以前の「従来のプログラム」は全て書いた通りに動いていました。人間はミスするかもしれませんが、プログラムはミスしません(ミスしたのはそのコードを書いたプログラマーのほう)。一度書いたプログラムは未来永劫同じように動きます。
この性質は「柔軟に判断できるがミスをする」人間と「柔軟性はないがミスしない」機械でうまく補完しあうようにできていました。
一方でAIはどうでしょうか。
AIのバックエンドにいる LLM は本質的に確率で動いています。次に来るトークン(単語や文字の単位)を確率的に予測し、それを繋げて文章やコードを生成しています。これによってAIは人間のような柔軟性を手に入れましたが、かわりに人間のようにミスする機械になりました。
確率で動いている以上、どんなにプロンプトを工夫しても、どんなにルールを整備しても、100%正しい出力が得られることは原理的にありません。つまり、性質的には 人間と補完しあう機械ではなく、 むしろ 人間サイドに立つ機械 だと言えます。
AIに定型コードを書かせるな
定型的なコードをAIに書かせるような場面はそれなりに存在すると思います。しかし繰り返し同じようなコードを書かせていると、たまに「こいついつもと違うコード書いてんな…」となることがあります。
前述の通りAIに絶対はないため、毎回同じ指示を出したとしても微妙に違うコードを書くことがあります。これではAIの出力を信用しきれないため、毎回レビューする必要があり非常にダルいです。
ここで、一昔前の自分が同じ状況に遭遇したらどうしていたかを考えてみましょう。「コードを書くコード」を書く…つまりメタプログラミングをしていたのではないでしょうか?
メタプログラミングは(AIではないという意味で)従来のプログラムなので、一度書けば常に同じ出力を得られるメリットがあり、この点においては AI よりも優秀だと言えます。
AI に「定型コードを書くコード」を書かせる
とは言ってもメタプログラミングは普通のプログラミングよりも面倒だし、面白くないですよね。
じゃあ AI にメタプログラミングさせればいいじゃないか!
メタメタプログラミングの幕開けです1。
このように AI にメタプログラミングさせることで、
- AIが書いたコードのレビューは最初の1回だけで良い
- 完成したコードからは毎回同じ出力が得られる
という、新旧プログラムのいいとこどりをしたような結果が得られます。
具体例:C# の Source Generator
これをうまく活用できる例が、C# の Source Generator です。
Source Generator は、コンパイル時にソースコードを解析し、追加のソースコードを自動生成する仕組みです。Source Generator はドキュメントが少なく、人間がゼロから書くには少しハードルが高い技術なのですが、それなりに多くの実例が存在するため、AIは結構ちゃんと書いてくれます。AI が書いた Source Generator のコードを読むのも少々しんどいですが、出力が正しいことをもってレビューに代えてもよいでしょう。
AIに Source Generator を書かせる際は、入力と出力の例をひとつずつ渡し、コメント等で対応付けを補足することで精度が上がります。
> @Hoge/Person.cs のような `AutoNotify` 属性が付いたクラスから、
@Hoge/Person.g.cs を生成するような SourceGenerator を書いて下さい。
[AutoNotify]
public partial class Person
{
private string _name;
}
public partial class Person : INotifyPropertyChanged
{
public string Name
{
get => _name;
set
{
if (_name != value)
{
_name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Name)));
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
}
「AIに『定型コードを書くコード』をうまく書かせる」プロンプトを書く
ここまでできたら、あとは Claude Skills や Cursor Rules などの仕組みを使って、AI がうまくメタプログラミングできるように適切な基盤を整備してあげましょう。
メタメタメタプログラミングです。
C# Source Generator の場合、特に何も指示しないと AI は Incremental Source Generator の仕様に沿っていないメタプログラミングをしてしまうことが多かったため、このあたりを補足してあげると良さそうです。もちろん、仕様書などを読み込ませてこの基盤自体をAIに生成させる(メタメタメタメタプログラミング)のも良いでしょう。
CreateSyntaxProvider メソッドを呼び出す際の注意
* predicate 引数に指定するメソッドは十分に負荷が低くなるように注意
* transform 引数に指定するメソッドの戻り値は比較可能な値とする
* ITypeSymbol のようなコード要素を含めないこと
おまけ: AIにレビューさせるな、レビューするコードを書かせろ
メタメタプログラミングを推奨するのと同じ理由で、AI にレビューさせるかわりに linter などの「レビューする仕組み」を作らせるのもおすすめです。
特に C# であれば、独自 linter に相当する Source Analyzer の仕組みが Source Generator と同じ基盤上に構築されているため、ある程度プロンプトを流用できます。
まとめ
- LLMは確率で動いているため、100%正しい出力は原理的に得られない
- 従来のプログラムは書いた通りに動く
- AIに定型コードを直接書かせるより、定型コードを書くコードを書かせる方が効率的
AIの力を最大限に活かしつつ、100%の信頼性が必要な部分は従来のプログラムに任せる。
このように新旧技術を適切に使い分けて、楽しくメタメタメタプログラミングしましょう。
株式会社アプリボットでは、 エンジニアをはじめ全職種で積極採用中 です。
記事を読んで少しでも興味を持たれた方やお話を聞きたい方は、是非お気軽にご連絡ください!
-
AI にコードを書かせることを「メタプログラミング」と言うのはあまり正しくないかもしれませんが、話をキャッチーにするためにお許しください。 ↩