GitHub Copilotを使うようになった

ある日突如として私の生産能力を3倍に引き上げるべく1、上長による稟議承認が30分くらいで行われてGitHub Copilotのライセンスが割り当てられた。やるからには効果測定をしないといけないということで、基本的にコードを書くことは禁じられて、すべては生成AIコードエージェントが書いたコード任せにすることになった。

自分で書いた方が早くない?

正直な話、今のところは生成AIの出力するコードは品質的に満足できるものでなく実用に耐えない。しかし、補完機能については直し忘れ防止のために役立つこともあるので悪くないと言えるが、ほとんどは余計なお世話なのでEscキーを押している。たまに理想通りのコードが提案されてTabキーを押しているだけでコードが次々と生成されて様子を眺めていると脳汁が出るのが自分でもわかる。

私「口だけは達者な生成AIばかりよく揃えたもんですなあ。全くお笑いだ。メイトリックスが見たら奴も笑うでしょう」

商材屋「私の生成AIコーディングエージェントは皆超有能だ」

私「ただのカカシですな。俺達なら瞬きする間に(指パッチン)実装できる。忘れないことだ」

利点

私はMarkdownに書いてそれを指示として与えているのだが、やりたいこと・手順・注意点等を書いており、それ自体が証跡となるので、あとから見返して指示した理由と内容が明確であるし、コードの変更だけでは読み取れない文脈や設計思想も記録として残る。コードと一緒に指示ファイルもコミットすれば、Gitのコミットメッセージでは書ききれない変更履歴まで確認できるわけだ。

毎回書くような指示は後述のカスタムエージェントに与えるべきだし、知見としてまとめていけば次第に自分の理想とするコードを出力できるようになっていくはずだ。

カスタムエージェントの導入

毎回細かい指示を与えているわけにはいかないので、流石にカスタムエージェントを追加した。業務ではC#を主に書いているので、それを想定した指示を書いては指示をした結果、とんでもない修正をされたわけだが、トライアルアンドエラーで禁止項目として追加していった。

今のところは既存のプロジェクトの改修に使用しているので、いちから作るコードとは異なる点があるかもしれないが、強く感じた課題は次のとおりだ。

  • 中括弧 (Curly Braces) の一致を認識していない
  • 信じがたい場所にコードを挿入する
  • コードクローンを挿入する
  • 不要な空白行を挿入する
  • インデントレベルがおかしい
  • そもそも指示に従わない (マジでキレそう)

なので、多くの作業に関して「指示がない限り、絶対に〇〇しない」という制約を追加することになった。また、具体的なコード例がないとうまく動作しないものもあり、特に #region ディレクティブ2をうまく挿入するのには苦労した。

言語ごとの定義ファイル

.github/instructions/{name}.instructions.md ファイルを作り、

---
applyTo: '**/*.cs'
---
 
- 基本的なコーディングスタイルはオールマンスタイルに従うこと

などと書いておくと、特定のパスパターンに対して有効な指示を与えることができるらしい。しばらく試したところでは、こうしたファイルがあっても一般的な質問に対してはエージェントファイルに「質問内容から言語を特定できる場合は適切なMarkdownファイルを読み取って回答に適用する」と指示しないと期待した回答にならないようだ。

C#のコードの品質に対する疑問

1週間ほどかけてかなり調教しても、ネットでみんなが言っているほどのいいコードが生成されない。その間に少しPythonのコードも修正したところでは、概ねうまくいったところを見ると、C#については以下の状況があるため、自分が望む結果が得られないのではないかと考えた。

  1. 文法の自由度が高い
  2. エンタープライズ利用が多くサンプル数が少ない
  3. ネット上にあるコードの質が高くない

Google Geminiにこの疑問を投げつけたところ、文法の自由度が高いというよりも、言語の進化によって書き方が多彩になってしまい、今も進化し続けているため、昔のコードとも断絶が発生していることが問題だそう。さらにサンプル数はあるものの、チュートリアルや断片的な質問サイトの回答に限られ、有用なコードは外に出てこないことも一因らしい。

そう考えると生成AIを使ったC#のコーディングで満足いく水準を保つのはかなり難易度が高いのではないか?と思わざるを得ない。文法的な観点ではPythonはオフサイドルールで厳格だし、GoやLuaはシンプルな文法を持つので有利と言える。Rustも自由度こそ高いが、壊されにくいという逆の理由で実用に耐えうる。JavaScriptはコードが無数にあるので、コーディングスタイルを縛り切ることができるのであれば、今や一番恩恵を受けられる言語かもしれない。

自分の要求レベルが高い?

これはあるかもしれない。コードに要求する美意識が高すぎるところはあると思うので、かなりガチガチに縛らないと自分が納得する出力が得られないので悩ましい。

少し友人に相談したところ、「品質60%を許容する感覚になると急激に実装が進む(後のことは考えないこととする)」などと返ってきたので、生成AIコーディングは私のようなコード潔癖症には向いておらず、とにかく今の段階では素早く課題を解決するためのコードを出力させるための道具なのかもしれない。

しかし「バルク操作をするために効率的なSQL問合せをして」と指示したところ、

public async Task<IReadOnlyList<User>> GetUsers(IEnumerable<string> userIds)
{
    foreach (var userId in userIds)
    {
        // 毎回SQL問合せをするコード!
    }
}

を出力してきたので頭を抱えた。やはりコードの質が高くないと考えられるので、求めるコードの品質を満たすための知見をすべてエージェントに伝える必要があるのかもしれない。そうしたときにやっと自分と同じレベルのコードが生成できるのかもしれないが、かなり険しい道のりと言える。

これって持続可能性があるの?

焼畑的に感じられる

しかし生成AIコーディングしていると、今は過去何十年間の人類の知恵を使えるが、これから10年経っても同じだけの価値を提供できるのかどうかという疑問が湧いてくる。おそらくそのころには、みんなが生成AIに頼るだけになってしまって、自動生成されたコードだらけになるだろう。そしてそれを再学習した結果、生成されるコードもどれも似たか寄ったかのぬる~い品質のコードに収束していってしまうのかもしれない。

行き着くところに至った場合、誰が質の高いコードを提供して、誰が質の低いコードを弾くのだろうか?そしてそれをできる人は残されているのだろうか?今や知識を電気で消費する焼畑的な活動をしているのではないかとも感じるのだ。

生成AIに汚染されてはならない

これによってある程度の水準は担保されるものの、みんなが同じコードを使い回すので、セキュリティ的な不具合を抱えたコードを生成することもあるだろうし、CVE的な形で報告することも難しくなるだろう3

先日もフロントエンドから直接データベースに問合せをして炎上したサービスや、ファイルアップロードサービスを不適切に活用するコードを生成する事例があったが、素人でも極めて短時間で成果を出せるようになったという技術革新は認めつつも、体系的な知識不足や倫理観の欠如が課題となっており、やはり生成AIより人間のほうが賢くあって知識を持ち合わせてなければならない。便利な道具の登場によってクリエイティブな活動の参入障壁が低くなったことは喜ばしいことだが、いわゆるスクリプトキディ的な行動がこれまで以上にやりやすくなってしまったのは残念だ。

Footnotes

  1. 給料は変わらない。

  2. コードの一部を折りたたみして整理するためのディレクティブ。例えば「プロパティ」や「コンストラクタ」などでグループ化している。

  3. ベンダー側が特定のコードを出力しないように対策を入れる可能性はある。